Opus Magnum

Opus Magnum

362 vurderinger
How to golf your solution
Av NYKevin
Tips for optimizing problems you've already solved.
4
2
2
6
   
Utmerkelse
Favoritt
Favoritter
Fjern som favoritt
Fundamentals
"Golfing" is a term from the recreational programming community. "Code golf" is a game where you try to solve a problem in a given programming language with as few characters as possible. There are other kinds of golf. Programs can be golfed for speed, complexity, or aesthetics.

In the context of Opus Magnum, golfing means minimizing the number of cycles, the area, or the cost of a solution. It is usually not possible to optimize for all three at once, though area and cost often go together.

In most cases, area and cost can be minimized by using a single arm with a long and complex series of instructions. Optimizing for cycles is much more complicated. Therefore, the rest of this guide focuses on cycles exclusively.
How the timeline works
The timeline is the set of tiles at the bottom of the screen. It controls the order in which things happen, and also decides when a component will wait instead of doing something useful. The rules may be a little unintuitive at first, because they are designed to do the "Right Thing" for any design.

Each component has a series of instructions. If you leave empty space between two instructions (but not at the beginning of the timeline), the game will automatically fill in blank instructions. Blank instructions always count as "real" instructions. Every instruction takes exactly one cycle to execute. The blank space at the beginning of the timeline doesn't count, because the game only executes that delay the first time through.

The whole machine has a period. The period of the machine is simply the number of cycles it takes for the whole machine to repeat. Whichever component has the most instructions will determine the period.

The game will not allow a component to get out of sync with the rest of the machine. So if a component does not have a full period's worth of instructions, the game will simply pad it with empty instructions. This appears as a light background after the end of the instructions you placed.

As an example, suppose you have a simple machine like this:
  • Arm #1 has two instructions, with no space at the beginning.
  • Arm #2 has three instructions, plus an extra space at the beginning.
  • Arm #3 has five instructions, including a gap in the middle.
  • Arm #4 has six instructions.

In the editor, it looks like this:


When you click the step button, it changes to this:


The period of this machine is six, because arm #4 has the most instructions. So:
  • Arm #1 is padded with four empty instructions, because 6 - 2 = 4.
  • Arm #2 is padded with three empty instructions, because 6 - 3 = 3. The empty space doesn't matter.
  • Arm #3 is padded with one empty instruction, and the gap also turns into an empty instruction, for a total of six.
  • Arm #4 is not padded, because 6 - 6 = 0. Again, all of the empty space at the beginning is ignored.

Understanding how the timeline works is crucial to golfing your solutions correctly. In general:
  • Each arm will only run its instructions once before the machine repeats. If you need an arm to do the same thing more than once during the whole machine's period, use a repeat instruction.
  • You can use the clock instruction to make the machine's period longer. This affects the whole puzzle, so you only need one clock. Most of the time, you don't need the clock at all.
  • Empty space at the beginning of the timeline mostly doesn't matter. Empty space in the middle of the timeline does count, and so does empty space at the end.
  • Empty time that counts usually results from waiting for another component. If you can get that component to go faster, you can have less empty time on your timeline.
Identifying bottlenecks
As we discussed earlier, gaps in the middle or at the end of your timeline slow down the machine, because components have to wait for each other. When you see a lot of gaps, you should look for a "bottleneck." This is the part of the machine that is slowing down the rest of the machine the most.

Here's a simple example:

Obviously, this isn't the best design. But what, specifically, is wrong with it?

The problem is the arm on the right. It is doing too many things. You can tell because it is moving constantly, unlike the arm on the left. A constantly moving arm indicates that the game did not add any padding to the timeline, so it must have the most instructions. The component with the most instructions always determines the machine's period, so the right arm is slowing the whole machine down.

Therefore, if we can make the right arm work faster, we will speed up the whole machine. On the other hand, speeding up the left arm won't help (yet), because it would just end up waiting for longer.

In this case, the solution is straightforward: Add a third arm, which does some of the work currently done by the right arm. Once we do that, we get a design like this:

This is a little better, and saves a few cycles, but a real improvement would require more arms. Right now, both of the fixed-length arms are responsible for two atoms, but it would be more efficient if each only had to attach a single atom. You can clearly see that each fixed arm is spending a lot of time moving, and not much time waiting.

For the final version, we also moved the calcification glyphs so that the fire and water atoms get calcified after bonding. We did not need to do this; we could just as easily have calcified them while the new piston arms were moving the atoms around. But it is often easier to bond first and then calcify, because you can move the whole molecule over the glyphs as a unit.


Further improvements are possible, of course, but this is probably Good Enough for now.
Multi-arms
One of the simplest optimizations is to use an arm with more than one gripper. Arms with multiple grippers can reset faster than arms with one gripper. For example, the cover image for this guide (see right) shows a triple arm, which doesn't have to reset after rotating. As a rule of thumb:
  • Arms that rotate three times and then reset should be double arms.
  • Arms that rotate twice and then reset should be triple arms.
  • Arms that rotate once and then reset should be six-sided arms.
Once you've made these substitutions, you can replace any reset instructions with a single release instruction, which saves a lot of time.

When performing this optimization, test your changes carefully before proceeding. In this example, it works because the molecule vanishes as soon as we drop it on the product slot. But if you want the molecule to stick around for a while, your arm will pick it right back up again, unless you move it away with another arm.

You can also see that we didn't bother optimizing the two single arms into six-sided arms. That's because the triple arm is constantly moving in this solution, so it's a bottleneck. We can't make the machine any faster without making the triple arm faster. Regardless, six-sided arms would need to wait for each other to avoid both grabbing the same atom at once, so the single arm approach is already optimal anyway.
Translation vs. Rotation
"Translation" means moving a molecule in a straight line, using a piston or track. "Rotation" means rotating a molecule with an arm. There are important differences in how these two kinds of motion work.

Translation always costs one cycle per hex. It preserves the orientation of the molecule and is particularly well suited to making long polymers or infinite products. It's also quite easy to modify the molecule as it passes, for example by bonding or calcifying.

Rotation costs one cycle for every sixty degrees you rotate through. The distance is irrelevant; a long arm rotates just as quickly as a short arm. As a result, rotations are well suited to larger non-polymer molecules, and situations where you need to move through a lot of hexes quickly. The downside, of course, is that the molecule will pass through a larger number of hexes on its way there, and you need to keep these hexes clear of obstructions.

While we're on the subject of tracks, we should point out a couple of neat properties. You can arrange a track into a closed loop, which will then allow arms to return to their starting points by going all the way around. You can also place multiple arms on the same track, but they must not collide. Combining these tricks, you can have one arm translate while a second arm resets, which allows for substantially greater throughput on polymer molecules.
Inputs vs. Outputs
When you're trying to figure out whether a large, complicated machine is optimal, it can be helpful to think in terms of inputs (reagents) and outputs (products).

In general, most machines do not build up a large store of atoms. Every input atom or molecule that is consumed is eventually processed into an output (or in later levels, unceremoniously destroyed). Any machine occupies a finite area, and would eventually run out of space. So, once your machine is running at steady state, the rate at which it produces outputs (in cycles per atom) must be equal to the rate at which it consumes inputs (after accounting for different types of atoms, e.g. a tin atom equals a lead plus a quicksilver, or two lead).

The bottom line is this: At steady state, if you are consuming inputs as fast as possible, then you are also producing outputs as fast as possible. A good way to gauge the speed of your solution is to look at the inputs. If your machine is constantly pulling atoms and molecules out of the reagent slots, then it's probably very close to optimal, though you may be able to improve its startup time. If the reagent slots are sitting idle a lot of the time, your machine could probably be a lot faster.
Conclusion
There are a lot of different ways to improve your solutions. Always be vigilant for opportunities to squeeze extra cycles out of common operations. Most interactions (bonding, calcification, etc.) happen in one cycle, but moving an atom can take three or more (grab, rotate, release), so there's almost always room for improvement.

But remember: You can't golf what doesn't work. If you're getting frustrated because you just can't find a sensible way to do something, just build a slow version and iterate. You'll get to a better design eventually.
28 kommentarer
Maxar 14. nov. 2023 kl. 10.47 
Perhaps performance is more impactful than cost in the long run, but generally, in computers and programming, designing for performance without consideration for cost can lead to inefficient system design in terms of power consumption or operating costs.
Don Swet 13. nov. 2023 kl. 13.52 
Oceano is correct. In programming, you want to maximize reciprocal throughput. AKA how much stuff is being generated per hour. That's cycles.
Oceano 26. sep. 2023 kl. 12.10 
I disagree, Maxar, even if the client is not rich, in the long run a machine that can produce more per hour is much more desired than one which can produce less, unless the initial cost is so high that it would take several years to pay off.
Maxar 18. jan. 2023 kl. 19.00 
In my opinion, if there is one thing you should golf for, it's usually lower cost, not so much lower cycles. Unless the client is rich and money doesn't matter so much, the priority goes cost, cycles, and then area.
levet.byck 12. feb. 2021 kl. 10.43 
Can't say it's helping much, but sure I got new terms and concepts to play- and joggle with..
Should revisit this, once I understand "something" better
Edit: My idea was that you actually could calculate how many hex's/components that potentially could be put in use in each solution - something about understanding the dimension of the product(s) vs reagents - an input to output equation-thing (as if using an integral equation)
Ethrin 19. jan. 2021 kl. 16.58 
This was a great walkthrough. Thank you for taking the time to write it up. It helped me identify some issues with my designs.
bassaly 26. des. 2020 kl. 14.41 
Thank you for this well compressed information. Reasonable and intelligent, the essences clearly visible. I follow these instructions and can confirm that they help.
Baked Potato 22. mai 2020 kl. 23.32 
You are missing a picture in the bottleneck section:

"In this case, the solution is straightforward: Add a third arm, which does some of the work currently done by the right arm. Once we do that, we get a design like this:

This is a little better, and saves a few cycles, but a real improvement would require more arms."
manyuser 9. mars 2020 kl. 6.50 
I am addicted to conveyer belts of arms processing small products at maximum speed for enormous cost. Please help. (It should be noted that the time of the initial cycle can increase pretty quickly like this, so rotation can often be more efficient as stated.)
dholland 15. okt. 2019 kl. 15.16 
Helpful guide. About tracks: they allow you to reduce the period to the minimum value possible. In theory, arms following each other on tracks can have period 2 at the least. Note that arms without tracks have minimum period 3. Without tracks you tend to have arms of different individual periods adding to the total period. Yes, you can add a few more arms to harmonise arm periods without tracks, but if your arms are not perfectly parallel you're adding to the total period when you do this. The actual minimum will depend on the complexity of processing necessary. The cost is complexity and size: you have multiple arms on the same track and a lot of instructions to debug. With tracks, you can avoid to a great extent the costs of harmonising arms and gain the speed of doing as much processing with a single arm as is helpful. Translation is essentially a free instruction (doesn't increase period).