The concept of connectivity has a long history in board games. In fact, one of the maybe oldest board games that is still influential, Go, is entirely centered around the concept of connectivity. One can describe the rule of Go (the Chinese version) in a few clauses:

- Players take alternative turns to put stones or pass. Two consecutive passes end the game.
- Whenever one puts a stone, the board is checked: if a connected component of stones of the same color does not have an adjacent vertex without a stone, the whole connected component is removed. The connected components of the enemy color is checked first.
- Non-pass moves that lead to the same board situation are prohibited.

There are many different versions of the third clause, and different conventions used in actual games, but that’s beyond the point. What is interesting is the second clause, which is so simply explained in a graph theory terms.

Such is the charm of the concept of connectivity. It is easily understood by all players of all ages. It is, on one hand, so abstract in nature, but on the other hand, super intuitive and graphical.

And in the scene of modern, European-style board games, we have Carcassonne as a probable forerunner.

The game, if you have not played before, can be introduced shortly and with great simplification:

Players take turns in placing randomly drawn tiles and workers. They get score by finishing castles (connected components), roads (paths with both ends defined, or loops), cloisters (a tile and all adjacent tiles), and getting extra score by owning pastures adjacent to finished castles.

Again, the concept of connectivity plays a very central role in this game. Part of the fun is to find creative ways to attach an extra tile to a half-finished castle or merge pastures in unexpected ways.

In some sense, I would even say that the point of bothering about boards is connectivity in the graph theory sense. It is something that cannot be replicated with cards, dice, whatever.

A sub-genre of modern board game feature the lack of randomness. Or, if we use positive nouns, I would say “determinism”. It means there is no deck shuffling, dice rolling. For classical board games like Chess and Go, this is basically taken for granted.

However, modern (non-abstract) board games, while offering more themes and more different ways of interaction between the players, rarely take the deterministic option. The reasons might be manifold:

- randomness itself can be fun;
- games with randomness usually have more replay value: even if the players are boring and just repeat the same tactics from game to game, they still get to deal with new situations.

However, I think I should determine between three flavors of randomness:

- randomness in game setup;
- randomness explicitly built in the game;
- randomness induced by hidden information or simultaneous decision.

The first two flavors should be self-evident. The third flavor, however, is a bit hard to understand. However, one might examine Rock-Paper-Scissors: the game has no explicit rules for randomness, however, since it involves simultaneous decision, the players have to “create” some randomness out of nothing in order to maximize their winning chance — or rather, minimize the risk their opponent notices their pattern and beats them.

Usually, the games without explicit randomness tend to be deeper and more serious.

Caylus is an example of a game featuring absolutely no randomness. Unfortunately I have not played it before.

Dominion, another game I love, features two kinds of randomness: set up randomness gives each game a completely different board, then explicit randomness (in the form of shuffling) asks the players to adapt their strategy to their luck in draws.

A example with a game featuring set-up randomness but not the other two kinds of randomness is Terra Mystica.

In this building game, each round the player is provided a mana pool and a huge array of options. Players take turns to execute one action out of a very long list of permissible actions. But what makes it very tight and deep is that many actions can be taken only *once per round*; while other options can be taken only *once per game*. Needless to say, there are many thinking revolving around the valuation of each option. If one desperate needs an option but correctly reads that the opponent does not need that option at all, he might be able to take it later than his instinct tells him so.

The set-up randomness causes each game to have slightly different scoring goals and different list of options available.

It all worked well. Set up randomness ensured each game would be different.

Still, I always wanted to be able to play the game on randomized maps. Unfortunately, it never happens. Even its evolution, Gaia Project, while featuring modular maps, still does not come with an official way to randomly generate playable maps.

Now let me talk about *that game*.

Thematically, it is the manifestation of pure and raw capitalism. You are for profit. The game is all about money. You run a restaurant company, hire interns to save cost, run advertisements to create spurious demand, then supply food and drinks to such created demands for profit.

Mechanically, the game starts with a randomly generated map, and players take turns placing their initial restaurant. The random map is borderline between “connected” and “not connected” — usually most places are connected but often via contrived connections. Sometimes there are simply two or more connected components. In other words, the density of edges seems to have been carefully chosen so that the connectivity of the resulting maps have the maximum variety.

After the initial placement, each player vote how long the game will last — however the vote result is *not* immediately revealed.

Players have a number of employees at any time of the game. Of course, they stat with no employees. Each employee can be fired, put to work or in vacation.

In each round of the game, the players decide what to do with each employee, *simultaneously*. Then the players decide their new order of action based on the number of *vacancies* in their company as well as the old ordering. Then the players take their turns in this order, doing all kinds of stuff such as hiring people, training people, running advertisements, producing food and grabbing drinks.

I am not going to detail in how each action means. However, we can clearly see that the game features two kinds of *implicit* randomness: in the voting process, and in the simultaneous decision in each round. The voting process has the extra property that it is a hidden information generated by players that would only be revealed in later stages of the game.

In practice, these decisions often *do* matter. For example, waitresses do not have great use, but the player featuring more waitresses in work wins the “waitress battle”. Similarly, discounts work the best if you put just enough discount to “win over” all the customers that could have gone either way. Sometimes the order of the turns matters the most, but having too many vacancies hurts, so one prefers beating their opponent with just *one more vacancy*.

In each of these cases, the Nash equilibrium is a *mixed strategy*. Just like the classical example of Rock-Paper-Scissors, this game creates randomness from nothing. However, since all the randomness is generated by players, it feels more natural than the “enforced randomness” in the more explicitly random kinds of games.

Furthermore, the game features many *milestones*. If the game itself is a parody of the capitalism world we all live in, the milestone system is a parody of all the “achievement” system in video games we all play. A milestone will be rendered unreachable at the end of the round someone reaches it.

Anyway, one of the milestone has particular game theory interest, as it says “if you reach $20, you can peek at the voting result”. It puts another twist to the voting process: you can’t change the voting result with that milestone, but you get the hidden information earlier than other players. There is, technically, no inherent randomness in the hidden information, but it could still hold considerable sway in the game strategy.

I wish I have highlighted why I love this game. In addition to its lovable complexity and it being generally well-designed, it features a rare combination of set-up randomness and implicit randomness. Furthermore, the random set-up process involve putting together a map with randomly drawn and randomly rotated tiles. The inherent beauty in connectivity makes each map unique and provide a different challenge for the players.

]]>

Realistically, though, amateur footballers should be very wary of moving in long distance. After all, being amateur means that they are either students or have another job. No matter how much they love football, they need to live and that should put a constraint on how often they are willing to move to another city.

OK. I should stop with these complaints. I am playing a custom database after all. It’s not official.

The last post mentioned Boukhari, Netteb, Sporkslede, Balkestein and Jörns. Unfortunately, early in the season Boukhari was signed by another team with higher reputation, so I had no chance to actually use him in a single match. And with the signing of a slightly better assistant manager, it turned out that Balkestein and Jörns were not as good as their initial rating look like.

Fortunately, I also signed additional players in pre-season. Sjors Beckers immediately became my captain.

The addition of Giel Piereij was trickier since he wasn’t that proficient as a striker and I didn’t have a place for a attacking right midfielder. After a few matches, it became obvious that I should fit my formation to my available players instead of the other way around, and now I play an asymmetric 4-3-3 formation to accommodate for Piereij.

While the signing of the above two players were immediate success, Luiza had a much less impact. His super low determination proved to be detrimental as part of the social group, and he was too injury prone to contribute anything consistently.

The youth intake was probably brokenly strong for this level. Why do amateur clubs have youth intake even. Anyway, no complaints for a custom database.

The cream of the crop were Maurice van der Wal and Rico Bosma. Also, Bosma was the first decent central midfielder in my team.

Among the late season joiners, Muhammed Nouri was the most useful. He and Beckers are also the only forwards in my team with decent finishing rating, a rare ability at this level to be sure. Why are low level forwards so often Poachers though?

I end up with the 4th place. As the first place is automatic promotion and the second and third places are promotion via play-offs, 4th place is basically the best place of earning nothing. However, I actually spent most of the season sitting in mid-table, so ending at 4th is definitely an encouraging message.

Some final thoughts. In this season long shots are crazily accurate and tend to score. I am not sure if it’s an engine thing or an amateur thing. But I have to admit that in low level matches, the attacking players often have hilariously long time to prepare for a long shot, so maybe that success rate is not that unreasonable. Still, this differs a lot from my stereotype about “low level league = strength, pace and jumping reach”. There are definitely much more subtleties to that!

The fans have different opinions than me and the various coaches about what players are the most valuable ones though. Mats Lagas (a late screenshot by the way) and Salah Jongebloet are their favorites.

]]>The post was this. I wrote about what my first game setup was like, and what difficulties I met with trying to run the game under Linux with Steam Play.

The page, available here, was on the other hand **not** supposed to be a publicly viewable page. At least not until I have added in more stuff. It contained various technical details of what I did to get my first game running, so that I could follow it step by step and continue my game on a second PC.

Naturally, both the post and the page were named “Football Manager 2019”. Guess what? The generated permalinks are also the same. For both the post and the page they are https://blog.ahyangyi.org/football-manager-2019. The page took priority over the post. Hence, even if the main page shows the correct digest of the post, clicking “read more” would show the content of the page instead. And it was a page that was supposed to be secret at that point…

There were, many different naming schemes that I could use. Unfortunately, I have already made the decision back in a time I did not know about any potential issue, and now it is perhaps a bit too late to change it, as I have used many internal links, this very post also adding to the injury.

What I did not expect is that there is no mechanism of conflict detection whatsoever.

It seems that, given all these considerations, I have to be careful with names.

]]>Anyway, complaints be complaints, I will start my first game.

WIth Steam Play, which is a modified and integrated version of Wine, Football Manager 2019 is still able to run under Linux.

However, just like back when one plays games under Wine, random parts of the game will cease functioning, which is annoying.

And even for parts that still work, the paths and conventions can be very inconvenient for Linux users. For example, I discovered that my cloud saves are put under the following path:

```
$HOME/.local/share/Steam/steamapps/compatdata/872790/pfx/drive_c/users/steamuser/Local Settings/Applica
tion Data/Sports Interactive/Football Manager 2019/cloud/games/
```

And when I install a custom database I need to install it here:

`.local/share/Steam/steamapps/compatdata/872790/pfx/drive_c/users/steamuser/My Documents/Sports Interactive/Football Manager 2019/editor data/`

Yet, when I want to delete those fake names, I need to visit a third place. That places happens to be the same as the old Linux versions though, so there is some relief.

So far the only thing that does not work for me is the tactics preset. However, I *really* want to have a look at the presets even if I know I am going to tweak them beyond recognition soon. For it my plan is to copy the save to a Windows installation, play it for ten minutes or so to see what’s going on for all those presets, then leave and continue under Linux.

This time I start with an amateur club, ASV Arsenal in Netherlands. This way I could say I am playing Arsenal.

Fittingly, I need to set myself to a weak profile. Still, I have enough points to afford a perfect attacking score and a decent determination. Everything else will be joke-leveled.

The starting team consists of three real players (Omar Boukhari, Xavier Netteb and Justin Sporkslede). By signing the grayed out players, however, I am also able to find randomly generated Sem Balkestein (from reserves team) and Rini Jörns (from U19; why do amateur clubs have U19 teams though?).

And here are their start-of-season stats.

]]>

Anyway, back to the topic. It began to feel clumsy to move the four boxes around. It is time to find a storage solution.

There were many awesome storage solutions available. Some of which involve specially crafted containers, which might be hard or impossible to buy from China. Others involve repurposing the vanilla game box.

One the greatest models is Sumpfork’s Divider Generator. A live version can be found here, and the source code can be found here.

I do have found a few problems however.

First, while the generator comes with myriads of options, hacking any new idea into it is surprisingly hard. The problem is that the generator does not really do all the layout controls. Instead, it relies on `reportlab`

to do so, which works on its own set of assumptions, completely irrelevant for our purposes.

Second, the default background images, while looking good on a low resolution screen, actually looks very pixelated on a high resolution screen and, more importantly, with a decent printer.

The second point resulted in me trying to hack in an alternative design that does not involve raster images. The first point ensured that my attempt was futile.

Instead of continuing trying to modify Sumpfork’s generator, I figured out that it might be easier if I simply typeset the divider cards myself.

Really, once you realize that what you need is just to *typeset* the divider cards, it becomes a much easier problem. As long as I can find a way to typeset a few cards on a page, and another way to control the card contents, I get a generator. What looks like an annoying problem might be in truth two separate easy problems.

For typesetting I use XeLaTeX, which I am not an expert of, but there is nothing you can’t get by randomly hacking a few macro packages and options.

For some reason I decided to do everything in a De Finibus theme…

For the content control, I might have wanted to write a Python program to manage things, but since my goal is only to satisfy myself, LaTeX macro functionality is more than enough for this purpose.

And… for a failure, I will use a different format to described what is the challenge and how exactly I failed at it.

Here is a rough timeline for what I was doing during the competition:

- 00:00 – 00:20: read the four problems, as well as think about them briefly. In the end I concluded that none of them look easy but I should start with the first problem.
- 00:20 – 01:10: solve problem A.
- 01:10 – 01:20: solve the easy case of problem B.
- 01:20 – 02:00: solve the hard case of problem B, but getting a Wrong Answer.
- 02:00 – 02:30: solve the easy case of problem C, while also debugging problem B.

In the end my solutions for both problem A and problem B worked, and problem C easy is never enough for me to enter the top 25.

Zillionim is a turn-based game for two players. Initially, 10^{12} coins are arranged end-to-end in a single line, numbered from 1 to 10^{12} from left to right. During a turn, a player must select 10^{10} consecutive coins and remove them. Two coins that were not originally consecutive do not become consecutive even if all of the coins in between them are removed.

On their turn, a player makes a valid move if possible, and then it is their opponent’s turn. If a player cannot make a valid move on their turn, they lose the game (and the opponent wins the game).

Because our engineers are still hard at work training our machine learning model to play Zillionim, we have created a simple AI that plays Zillionim by making random moves. The AI always gets the first turn. On each of the AI’s turns, the AI determines all valid moves and chooses one of them uniformly at random.

Can you beat this AI… at least most of the time (*499 out of 500 games for the hardest case*)?

The first part of solving this problem involves writing a naïve solution. It involves all kinds of boilerplate code you are going to write anyway, so in some sense a naïve solution is one or two lines of naïve code plus lots of reusable, useful stuff.

A naïve solution also provides a right perspective into the problem. In this problem, the current *state* of the game is a set of intervals with length of least 10^{10}. Each action is to pick a breaking point in an interval, and depending on where you pick and how long the interval is, it might break in two, or shorten, or disappear.

And it is also not hard to see that all intervals with length between 10^{10} and 2×10^{10}-1 are functionally the same: picking anywhere in such an interval would result in eliminating it. Let’s call such an interval “Type I”.

For intervals with length between 2×10^{10 } and 3×10^{10}-2, however, they can either be eliminated, or shortened to an Type I interval. Let’s call such an interval “Type II”.

A key observation is that you can produce short intervals at specific lengths, and the random AI is very unlikely to mess with your plan since it is usually busy with the longer intervals. The end result is when the original long sequence finally turns into a set of short sequences, the length of about half of these sequences is decided by you.

The magic interval length I use is 3×10^{10}-2. What’s special about it? When the AI picks a breaking point in such an interval, it *almost always* shorten to a Type I. On the other hand, I still have both options, meaning that I can still directly eliminate it when I need to do so.

My early game strategy involves pumping as many magical intervals as I can. The middle game strategy involves getting rid of all non-magical Type II intervals, because it results in a simpler situation, making analysis easier.

Now we arrive in a *late game*, already controlled by our early and middle game strategies. In a late game, each interval is either a Type I one or a magical one. Assuming the AI always taking the high probability option when dealing with magical intervals, simple combinatorial game theory tells us that a situation is losing if and only if the number of Type I intervals is even. And as long as there is at least one magical interval remaining, however, we can effectively “cheat” by invoking the elimination option of a magical interval, turning a losing situation for us into another losing situation for the random AI.

All in all, this is a incredibly simple solution because it basically throws all the complexities away and deals with what’s remaining. It turns out to be very reliable: I simulated 5,000 games and it won all of them. This is probably why this problem is the first problem, and why it has the lowest total score.

You have just finished cooking for some diners at the Infinite House of Pancakes. There are **S** stacks of pancakes in all, and you have arranged them in a line, such that the i-th stack from the left (counting starting from 1) has **P _{i}** pancakes.

Your supervisor was about to bring out the stacks to the customers, but then it occurred to her that a picture of the stacks might make for a good advertisement. However, she is worried that there might be too many stacks, so she intends to remove the L leftmost stacks and the R rightmost stacks, where L and R are nonnegative integers such that L + R ≤ **S** – 3. (Notice that at least 3 stacks of pancakes will remain after the removal.)

Your supervisor also thinks the remaining stacks will look aesthetically pleasing if they have the *pyramid property*. A sequence of N stacks of heights H_{1}, H_{2}, … , H_{N} has the pyramid property if there exists an integer j (1 ≤ j ≤ N) such that H_{1} ≤ H_{2} ≤ … ≤ H_{j-1} ≤ H_{j} and H_{j} ≥ H_{j+1} ≥ … ≥ H_{N-1} ≥ H_{N}. (It is possible that this sequence might not look much like a typical “pyramid” — a group of stacks of the same size has the pyramid property, and so does a group in which the stack heights are nondecreasing from left to right, among other examples.)

Note that the sequence of stacks remaining after your supervisor removes the L leftmost and R rightmost stacks might not yet have the pyramid property… but you can fix that by adding pancakes to one or more of the stacks! The *pyramidification cost* of a sequence of stacks is the minimum total number of pancakes that must be added to stacks to give the sequence the pyramid property.

While your manager is carefully deciding which values of L and R to choose, you have started to wonder what the sum of the pyramidification costs over all valid choices of L and R is. Compute this sum, modulo the prime 10^{9}+7 (1000000007).

The annoying fact was that I failed to think of a solution that can work for the hard test case. Instead, I roughly knew the solution for the easy case and that was it.

Before venturing deeper, take notice that the “pyramidification cost” is essentially the same thing as the volume of water that would have been contained by a container of the shape of a histogram of the remaining stacks. They are very different ways to describe the same mathematical stuff, but some people, like me, would find the water metaphor easier to work with than the pyramidification metaphor.

Only when I started to write the O(n^{2}) solution it turned out to be not so straightforward. I split the water volume into two kinds: the first kind is “ascending”, while the second kind is “non-ascending”. They are not exactly symmetric because we need to take account of the cases where there are multiple highest points, but for the sake of describing the algorithm, their difference is minor enough. Therefore, I will only describe the ascending part.

Actually, splitting the problem into two parts is the hard part. Dealing with the parts is easy. First, enumerate all starting points, or, using the terminology in the problem, enumerate L. For each starting point, enumerate all ending point in ascending order, maintaining the maximum point in the current interval as well as the “current water volume” in the interval. The “current water volume” only needs to be updated when the maximum point changes.

Once I had finished the O(n^{2}) solution, it became apparent that there were optimization opportunities. The water volume of the current interval only updates as we encounter a new maximal height. And by “updating” we mean “adding something to it”.

Similarly, lots of computations from different starting points are actually similar.

Taking this perspective, we look at an “ascending lake”. It turns out we know exactly how many times its volume gets counted! If the said lake is between *i* and *j*, then any interval that contains nothing before *i* that is higher than or equal to *i*, and contains the lake in whole, would count the volume of the lake once.

To calculate the total contribution of this lake, we need to find out for each position the leftmost position to its right that is higher than it, and the rightmost position to its left that is not lower than it. Both of which can be calculated in O(n log n) time with the help of an interval tree.

Two companies, Apricot Rules LLC and Banana Rocks Inc., are sharing the same datacenter. The datacenter is a matrix of **R** rows and **C** columns, with each cell containing a single server tower. Each tower contains intellectual property belonging to exactly one of the two companies.

At first, they built walls on the edges between cells assigned to different companies. This allowed orthogonally adjacent cells belonging to the same company to remain connected. Also, two cells x and y are considered connected if x is connected to a cell that is, directly or indirectly, connected to y. With this definition, it was possible that two cells assigned to the same company were not connected, which was unacceptable.

Both companies agreed to build narrow hallways running through cell corners that allow two diagonally adjacent cells to be connected directly. Let us write (i, j) to represent the cell at row i and column j. At most one narrow hallway can be built through any given vertex, which means either (i, j) and (i + 1, j + 1) can be connected, or (i + 1, j) and (i, j + 1) can be connected, or neither pair, but not both. Of course, only hallways between cells assigned to the same company can be built.

Given a matrix where each cell is labeled `A`

or `B`

depending on which company it is assigned to, find a way to add connections through diagonal adjacencies such that all `A`

s are connected and all `B`

s are connected.

I had no idea about the hard test case. The easy test case has the number of rows of at most 4, which enables some contrived dynamic programming where you store the connectivity in your state. Which I tried and failed to get done in 30 minutes.

My thoughts on the problem is that it is probably easier than it looks. That it is a planar grid really keeps its complexity in check. Here is the third sample input:

BBAA BABA BBAA

Funnily, I have been drawing more test cases on paper and none of them are essentially more complex than this one. I think the correct route for this problem is to take this observation and do something with it. The solution should be something like greedy algorithm (in that it always takes one option of the opposite one is obviously useless) and construction (in that after the greedy parts are done, the problem should boil down to a few patterns that can be solved with construction).

I will not write about the last problem since attempting it without finishing problem C would have been a huge mistake, and I did not interact with the problem in any meaningful way to talk about it.

I feel I started incredibly slowly. Reading all the problems and picking one of them is a good strategy when I can solve at least one of them quickly. Otherwise, I might as well just dive at the first problem and solve it while also warm up myself. Of course, there is also the question that whether I should start writing some code *before* the contest, but unfortunately, on the other hand I find myself tire rather quickly in coding competitions. If I have to make a trade off between these, then yes, I still feel I should have warmed up before the contest, as my mental stamina isn’t *that* bad.

I think I used a correct approach for problem A, but it turned out that I spent an incredible 40 minutes between implementing the naïve solution and the final solution. Some of the time was probably spent in thinking about problem B, but that would have been another mistake. I should focus on problem A anyways.

For problem B, it turned out that writing down the solution for the easy case helped me with the hard case. In other words, I knew how to solve the easy case, but I did not think about it *clearly* on paper, and had to think about the same problem again. If I could analyze it on paper as clearly as I did when I wrote the easy case solution, I might have saved valuable time to deal with problem C.

… and it comes to problem C. I should have noticed that solving the easy case is unlikely to help, especially when an easy case only solution is likely to be very contrived and contains little to no code reusable for the hard case.

Instead, I panicked when I realized I wasted so much time on problem A, and went to try hard to grab any point I could. It proved to be futile and detrimental for my overall chance of getting in the top 25. Which is, to be honest, never likely to happen though.

]]>

Upon further inspection, however, it turned out that the problem does not lie in the theme, but my understanding of blockquotes: quoting a problem statement is definitely *not* an appropriate usage for blockquotes.

A temporary fix for those problem statements is that I turned them into plain text paragraphs. It looked much less distracting, but it also made it harder to tell between the problem and the answer.

Further solutions might include a table, a different background color, or an accordion. However, as I am weary of fixing old stuff again and again, I want to take more time to decide on that one.

As making adjustments to the theme will probably become a new normal, it might be useful if I have a benchmark, a unified place to see all the changes to happen. Hence, I started a test page. Since as of now I only concentrate on blockquotes, there are only blockquotes in it at the moment. But in the future I could reuse this page to include more examples.

There is also a page for similar purposes created by the creators of the theme. It includes more stuff, and is part of the inspiration for my creation of the test page. However, seeing the test page in my particular configuration might be useful. And I might some day include stuff not included by the upstream one.

A curiosity I noticed when creating that test page is that blockquotes can have an `<cite>`

field, which usually represents the source or author of the quotation.

In default Kahuna, the quotation itself is in a big, italic and serif font, and the citation is in smaller, upright, all-capital setting of the same font. The kind of serif typeface they have in mind is Georgia or Charter — both featuring strong and even exaggerated serifs, which can probably compensate for the smaller font size nicely.

In contrast, the typeface I am using, Adagio Serif, does not feature very strong serifs. Hence, the smaller letters really look weaker and lighter.

I changed the block quote typeface to slightly lighter, and adjusted letter spacing and font size to balance the citation and the quotation. I feel I ended up with a more interesting kind of contrast than before.

]]>

Muriel is on the path to discovering two new elements that she has named Codium and Jamarium. She has not been able to isolate them yet, but she wants to start investigating some important properties, like their atomic weights, by indirect means. Since Muriel is working with a single isotope of Codium and a single isotope of Jamarium, their atomic weights are strictly positive integers.

Muriel managed to create **N** different molecules, each of which contains one or more atoms of Codium and one or more atoms of Jamarium, and no other elements. For each molecule, she knows how many atoms of each element are present in it. The molecular weight of a molecule is the sum of the atomic weights of all the atoms it contains.

As a first step towards figuring out exact molecular weights for the molecules and atomic weights for the two elements, Muriel wants to sort the molecules by strictly increasing molecular weight. To assess the difficulty of that task, she wants to know how many orders are valid considering only the information she has right now. An ordering of the molecules is considered valid if there exist values for the atomic weights of Codium and Jamarium such that the ordering is *strictly* increasing in molecular weight.

To give an example, we represent each molecule by the ordered pair of the number of atoms of Codium and Jamarium it contains. If Muriel has 3 molecules represented by (1, 1), (2, 1) and (1, 2), there are two possible orderings that can be strictly increasing in molecular weight: (1, 1), (1, 2), (2, 1) and (1, 1), (2, 1), (1, 2). The first ordering is valid for any assignment of atomic weights in which Codium is the heaviest of the two elements, and the second is valid for any assignment in which Jamarium is the heaviest. The only case remaining is when both Codium and Jamarium have the same atomic weight, in which case (1, 2) and (2, 1) have the same molecular weight, so no strictly increasing ordering can be produced for that scenario.

Unfortunately the problems are getting longer and longer…

And I think I spent at least one minute wondering why they are not simply *Codium* and *Jamium*.

Anyway, this problem is essentially asking how many proportions of relative weights for Codium and Jamarium are there for which two atoms have the same total weight. These proportions do not produce legal ordering by themselves, but they are separators of different orderings. Hence the answer is one plus this number.

The Pottery Palace is going to run a lottery featuring some valuable vases by the artist Cody-Jamal. The lottery works as follows:

- 100 people get to play in the lottery. Each player has a unique number between 1 and 100, and is given a single token with that number.
- There are 20 empty clay vases on a table, numbered 1 through 20. The vases have narrow openings that are large enough to accept a token, but small enough that players cannot look inside to see the contents.
- On the i-th day of the lottery, the player with token number i chooses a vase and puts their token in that vase. Since the vases are all identical (apart from their labels), every player will choose one uniformly at random and independently of all other players’ choices.
- On day 100, after player number 100 has inserted their token, the organizers shake the vases to determine how many tokens are inside each one. If there is
*exactly*one vase that has fewer tokens than any other vase, then that one is the “winning vase”. The organizers then pour out all of the tokens in that vase, and every player whose number is written on one of those poured-out tokens wins a vase! If multiple vases have the same minimal amount of tokens, nobody wins anything.

You have been hired to test the security of the lottery, and you will participate in some trial runs. The company will always assign you the number 100 — that is, you replace player 100.

You have found some ways to tamper with the lottery at night, but security is tight, so you can only do so much! Specifically, after each of the first 99 days of the lottery, you may do exactly *one* of the following:

- forge a token with the player number of your choice (between 1 and 100, inclusive), and add it to a vase of your choice. You are a very good forger: if there is a winning vase, any forged tokens in that vase will cause the players with those numbers to win (with one exception; see below).
- use a special camera to see the numbers on all of the tokens in one vase of your choice

You may perform different actions on different nights, and you may choose dynamically: you do not need to decide on all of your actions in advance.

On the 100th day, it is your turn to insert your token into a vase of your choice (you do not need to choose uniformly at random). You cannot perform any other actions on that day.

You know that if there is a winning vase with more than one token for the same player, it will be obvious that cheating has occurred and nobody will win. However, it does not matter if other vases contain more than one token for the same player because the organizers never see those tokens.

Your goal is to be a winner in at least 90% of the test cases.

This problem is, I believe, pretty revolutionary, as it requires you to provide a strategy that works good enough over a given distribution of inputs.

As I did not have many ideas for this question, I decided to start from a toy strategy and gradually improve it.

Since the goal is to ensure the vase with your vote to win, the sub-goals are to have a plan about what vase to vote, and to keep other vases from threatening that vase.

Hence, I mix the two options with a fixed pattern (which ended up in a 3:1 cycle).

For each *peek* attempt, we try to look at something that has greatest uncertainty (as in have not been peeked for long), as well as threat.

What is more weird is the strategy of forging votes. A intuitive strategy is to always hamper the current second placed vase (based on our best effort to predict), since this gives the current best vase a greatest edge over its alternatives. However, this strategy does not work well enough, presumably because we have absolutely no control over the other 99 voters, and they might simply ruin your plan.

A more refined strategy is to hamper the *ninth* placed vase first, then eighth, seventh… as the time goes by. Only for the last few rounds, we focus on the second placed vase to ensure the vase we pick is the winner.

The strategies, especially the one for the forgery operation, involves lots of hyper-parameters. Fortunately, by increasing the number of test cases, we can check whether each potential modification improves the strategy or not with pretty high level of confidence.

My first submissions at a locally measured success rate of 92% failed the official test… which I have to blame my bad luck. But further improvements brought it to 94% and nothing could prevent my code any more.

This problem also brings an interesting question: what if we approach problems like this with reinforcement learning? To be honest, I have not done much reinforcement learning so far, but this is a fascinating opportunity to try fun stuff.

The problem shares the same story with the first problem, so I’ll only quote the actual different parts.

As a first step, Muriel sorted the molecules by strictly increasing molecular weight. Now she wants to find out possible integer values for the atomic weights of both Codium and Jamarium that are consistent with the ordering. Since she is aware there could be many consistent pairs of values, she wants one that minimizes the atomic weight of Codium. If there are multiple pairs in which Codium’s atomic weight is minimum, she wants the one in which Jamarium’s atomic weight is minimum.

It is pretty easy to find a open range to represent all the feasible weight proportions between Codium and Jamarium. The problem is we need both of them to be integers. In other words, we are to find a fraction of smallest numerator that falls within a known region.

I immediately realized that this problem could be solved with a Stern–Brocot tree. Since it is a binary tree, with deeper nodes having both larger numerators and denominators, we only need a binary search to find the first node to fall in the range and output it.

Only after the competition and finding my solution accepted, I realized that the said binary search still degenerates to O(n) for extreme inputs…

Last year, we asked you to help us convert expensive metals into lead. (You do not need to know anything about the previous problem to solve this one.) But your country’s leader is still greedy for more lead!

There are **M** metals known in the world; lead is metal number 1 on your periodic table. Your country’s leader has asked you to use the metals in the treasury to make as much lead as possible.

For each metal (including lead), you know exactly one formula that lets you destroy one gram of that metal and create one gram each of two metals. (It is best not to think too much about the principle of mass conservation!) Note that it is possible that the formula for the i-th metal might produce the i-th metal as one of the products. The formulas do not work with partial grams. However, you can use each formula as often as you would like (or not at all), as long as you have a gram of the required ingredient.

If you make optimal choices, what is the largest number of grams of lead you can end up with, or is it unbounded? If it is not unbounded: since the output can be a really big number, we only ask you to output the remainder of dividing the result by the prime 10^{9}+7 (that is, 1000000007).

I can’t help but wasted another minute or two wondering about the terrible pun about lead and leader.

Anyway, first find out all strongly connected components and sort them from the destinations to the sources. Then for each SCC we can calculate its “optimal lead production per gram” by discussing all the cases (which is more than I initially thought).

A trick that helps a bit is to introduce an extended number type that includes 0, all positive integers modulo 10^{9}+7 and infinity, and build various operations over this type.

Not long after, however, I decided that maintaining a Bazel workspace is not the best use of my time. I worked on other projects, and created an unrelated open source Bazel workspace for my own enjoyment.

This post will be a brief introduction of this project.

In one word, Hermeticity.

Well, Google engineers working on Bazel probably reinvented this word when it comes to building stuff. The word means that the building process is completely reproducible, regardless what environment you use. And by “completely reproducible”, we mean that the output binary stays completely the same, bit by bit. It also means no timestamps and fixed random seeds during compilation, but if they help you locate a really obscure bug, why not?

Since I am also a Gentoo user, there is something I dislike about this. I want to randomly update dependencies and see whether packages break or not. But for more serious projects, maybe a better reproducibility is desired.

Of course, by default Bazel uses the toolchain and libraries in your system. In this case, there is not much hermeticity to talk about, as people with a different system configuration will produce different results than you. However, as long as you do not update your system, your builds will at least be consistent, which is still something not easy to pull off in other build systems.

Other benefits include remote caching. However, while it has been in Google’s version of Blaze for years, last time I checked it was very hard to get Bazel to use that functionality. Hopefully things have improved since then.

Astraeus workspace is a much less ambitious project. I grabbed a few BUILD files from tensorflow and other open source projects, and wrote a few BUILD files myself.

Currently, the biggest applications buildable with this workspace are VIM and Inkscape.

There are also many dependent graphic libraries for Inkscape. Mostly because they are also dependencies of Tensorflow, supporting these is easier than other kinds of packages, which I usually have to manually write the BUILD files.

It can be found here.

To be honest, I don’t know. Building stuff is too much chore, too little epiphany.

The event that triggered me to revisit Astraeus Workspace is that I discovered an Github issue opened in February. Alas, I have been neglecting Github for a few months. It turns out that Bazel itself is rapidly changing, and I should at least catch up.

Another long planned thing is to build a GCC toolchain with Bazel, then write a configuration for the toolchain. I am not sure what is the benefit, but that will make the little workspace an ecosystem on its own. This is the reason why I have been adding compiler libraries like gmp and binutils to the workspace, but progress has been very slow and I am not sure whether it can happen at all.

Another idea was to add a few random applications, then feed them to really nontraditional toolchains like Emscripten, and see what happens.

]]>Anyway, it turned out to be OK for me as the other problems were easy and I was good enough to enter the next round.

Our Battlestarcraft Algorithmica ship is being chased through space by persistent robots called Pylons! We have just teleported to a new galaxy to try to shake them off of our tail, and we want to stay here for as long as possible so we can buy time to plan our next move… but we do not want to get caught!

This galaxy is a flat grid of

Rrows andCcolumns; the rows are numbered from 1 toRfrom top to bottom, and the columns are numbered from 1 toCfrom left to right. We can choose which cell to start in, and we must continue to jump between cells until we have visited each cell in the galaxyexactlyonce. That is, we can never revisit a cell, including our starting cell.We do not want to make it too easy for the Pylons to guess where we will go next. Each time we jump from our current cell, we must choose a destination cell that does not share a row, column, or diagonal with that current cell. Let (i, j) denote the cell in the i-th row and j-th column; then a jump from a current cell (r, c) to a destination cell (r’, c’) is invalid if and only if any of these is true:

- r = r’
- c = c’
- r – c = r’ – c’
- r + c = r’ + c’
Can you help us find an order in which to visit each of the

R×Ccells, such that the move between any pair of consecutive cells in the sequence is valid? Or is it impossible for us to escape from the Pylons?

Basically, you are asked to provide a way to traverse a board of given shape under the constraint that each step consist of two grids that queens on them cannot attack each other.

It’s quick to come up with a few random constructions like repeating variants of knight moves. This kind of naïve construction actually works very well for large **M** and **N**’s. Actually, they are guaranteed to work if you consider two variants and both **M** and **N** are large enough:

- variant 1: keep using (1, 2) knight move, wrapping around the border using modulo. Once you reach the last line, you start in the first line but to one grid to the right.
- variant 2: keep using (1, 2) knight move, wrapping around the border using modulo. Once you reach the last line, you start in the first line but to one grid to the left.

However, the construction starts to fall apart for small **M** and **N**’s! I made the mistake of not having calculated how many special cases I needed, and it cost me lots of debugging time. It turned out the above-mentioned construction needs three special cases:

**M**=**N**= 4**M**= 3,**N**= 5**M**= 5,**N**= 3

Even taking symmetry into consideration, figuring out how the construction would fail for **M** = 3, **N** = 5 was not easy. Hence, a hybrid approach of construction and brute force search could have fared better in another poor day.

Last year, a bunch of pesky gophers took up residence in our orchard. We tried to change our line of work by opening up a miniature golf course, but it looks like the gophers have followed us here! Once again, we need to figure out how many gophers there are, but we cannot observe them directly because they are secretive and nocturnal, whereas we like to sleep at night. We do know there are between 1 and

Mgophers, inclusive.Our mini golf course is famous for having a small electronic windmill on each of its 18 holes. The i-th windmill has 2 ≤

B_{i}≤ 18 blades, which are numbered from 0 toB_{i}-1, clockwise. Each night, before going to sleep, we turn off the windmills and set each one such that blade 0 is pointing downward, which is important so that the windmills can charge up properly for the next day. However, we have noticed that when we wake up, the windmills have been disturbed. Since our mini golf course is in a windless area, we think the mischievous gophers must be responsible!We know that every night, all of the gophers emerge, one by one; each of them chooses one of the windmills independently and uniformly at random and rotates it counterclockwise by one blade. So, for example, for a windmill with 3 blades for which 0 is pointing downward, the first gopher to interact with it turns it so that 1 is pointing downward, and then the next gophers to interact with that windmill make the downward-pointing blade have number 2, then 0, then 1, and so on.

We have devised a plan. We designed our windmills so that we can easily change the number of blades (to modulate the difficulty of our course), and we will now take advantage of this! Each night, before going to sleep, we can choose the number of blades on each of the 18 windmills, within the given limits; we do not have to use the same number of blades on each windmill, or make the same choices every night. In the morning, we will observe the number on each windmill’s downward-pointing blade.

We have

Nnights in which to figure out G, the number of gophers. Can you help us?

Google, we need *more* gopher problems!

Anyway, it becomes apparent that using wheels of different numbers of blades on the same day is asking for trouble: you quickly lose the ability to infer any information. And fortunately we do not need to do that either: just by setting the numbers of blades to a list of preset numbers we can easily solve the problem via the Chinese remainder theorem.

The only caveat here is that the Chinese remainder theorem works when the divisors are **pairwise co-prime**. Some people might forgot that and try using only prime numbers, which will not be good enough to solve the problem. I picked ${7, 8, 11, 13, 15, 17}$ intuitively, and it was probably also the optimal array, in the sense of producing the largest product (2042040) under the given constraints.

During some extraterrestrial exploration, you found evidence of alien poetry! Your team of linguists has determined that each word in the alien language has an accent on exactly one position (letter) in the word; the part of the word starting from the accented letter is called the accent-suffix. Two words are said to rhyme if both of their accent-suffixes are equal. For example, the words

`PROL`

and`TARPOL`

rhyme if the accented letter in both is the`O`

or the`L`

, but they do not rhyme if the accented letters are the`R`

s, or the`R`

in`PROL`

and the`P`

in`TARPOL`

, or the`O`

in`PROL`

and the`L`

in`TARPOL`

.You have recovered a list of

Nwords that may be part of an alien poem. Unfortunately, you do not know which is the accented letter for each word. You believe that you can discard zero or more of these words, assign accented letters to the remaining words, and then arrange those words into pairs such that each word rhymes only with the other word in its pair, and with none of the words in other pairs.You want to know the largest number of words that can be arranged into pairs in this way.

Since we are dealing with suffixes, it is obvious that re-organizing the input data to a trie will help. Traditional tries deal with prefixes but it should be obvious to you that you want to do it backwards and store by suffixes instead.

Once we have that trie, a simple greedy algorithm can be run on the trie to produce the answer. Each node on the trie can produce at most one “rhyme-pair”, and any word in its subtree qualify for such a pair. Furthermore, it is always desirable (meaning it will not make things worse) to create “rhyme-pairs” at the deepest subtrees as possible. Hence, greedy algorithm works, and a simple recursive function defined on the trie will give the answer.

]]>