Skip to content

Tutorial 4.3 (Overriding layer)

Aerll edited this page Dec 28, 2023 · 36 revisions

Overriding layer

This is the last switch, that we haven't talked about. It looks like this:

OverrideLayer();

This switch affects whole runs, therefore if we want to use it, we need to do so after creating a new run:

NewRun();
OverrideLayer();

Ok so, what does it do? In short, it tells the automapper to modify the original layer. Normally, every automapper creates a copy of the layer before each run. Tests are running on the original layer, but the copy is modified. After the run, original layer is replaced with the automapped copy.

I don't expect you to understand this, but worry not, we'll now look at some examples, to see how the automapper behaves with and without overriding switch.

Override vs copy

I never mentioned it earlier, but we've been already using overriding in our examples, whenever we used Roll or Chance. Why does r++ need it for randomization? Because, as we already know, there is no way of choosing one rule randomly. Overriding makes it possible to simulate this. We could easily observe this with Roll, if it didn't enable overriding automatically. So let's imagine, that it doesn't. Here's how it would behave with and without overriding:

Insert(red, green, blue).If(
   IndexAt([0, 0]).Is(yellow)
).Roll();


As you can see, something weird happened to the version without overriding, even though we used a mask, it's all blue. Not a result we would expect. First let's have a look at what this line really does. Roll will generate the following rules:

Insert(red).If(IndexAt([0, 0]).Is(yellow)).Chance(33.3333);
Insert(green).If(IndexAt([0, 0]).Is(yellow)).Chance(50);
Insert(blue).If(IndexAt([0, 0]).Is(yellow)).Chance(100);

When we run this automapper without overriding, it will simply not know, whether something has changed, until the end of the run. Even if the automapper places red, it won't change the original layer and it will still appear as yellow. No matter what we do here, we will always end up with a blue map.

By using overriding, we give the automapper access to this sacred knowledge. In our case, if it places red, the layer it's automapping will be modified. Now the tile will appear as red and the other 2 rules will always fail. In other words, with overriding enabled, the automapper knows, what the preceding rules changed on the map.

When copy is better

Sometimes it is the case, that overriding is giving us wrong results. One such issue occurs, when we're building borders, but we test only a specific tile.

Imagine we have a layer, where some tiles are already placed and we don't want the automapper to touch them. For this, we need to use a mask.

Let's see what happens, when we try to create a wall, but we change the default behavior of IsWall. Instead of testing full tiles, we want it to only test our mask. We can do this by using TestIndices, which we will talk about shortly:

Insert(green).If(
    IndexAt([0, 0]).IsWall(top).TestIndices(red)
);


This time overriding resulted in some weird green vertical stripes, meanwhile copy does exactly what we expected. This is for the same reason as before. With overriding, automapper knows about every change, that takes place. The red shape keeps changing and our rule becomes valid for other tiles. Without overriding, the red shape won't change for the whole run.

Testing specific tiles

Some of the tests in r++ work on full and empty tiles by default and there are times, when we need to change this behavior. That's where TestIndices comes in. By using it, we overwrite default tiles with the tiles of our choice. Keep in mind, that not all tests have this option available. From what we know so far, only IsWithinArea, IsNotWithinArea, IsWithinRadius, IsNotWithinRadius, IsWall, IsOuterCorner and IsInnerCorner support it.

Here's an example of how we can use it:

Insert(1).If(
    IndexAt([0, 0]).IsWall(top).TestIndices(10, 255.V)
);

This will tell the program to generate tests for 10 and 255.V.

With TestIndices we can also swap full and empty by writing:

Insert(1).If(
    IndexAt([0, 0]).IsWall(top).TestIndices(0)
);