Skip to content

Instantly share code, notes, and snippets.

@DylanDmitri
Last active October 7, 2018 19:57
Show Gist options
  • Select an option

  • Save DylanDmitri/328b72dd40ec709cdcd31ec1013be8fc to your computer and use it in GitHub Desktop.

Select an option

Save DylanDmitri/328b72dd40ec709cdcd31ec1013be8fc to your computer and use it in GitHub Desktop.
Opus Magnum Suggestions

Opus Magnum

In search of better metrics!

Speed

  • cycles to first item
  • cycles to 6 items
  • long-term production schedule (average speed, batch size & pattern if applicable)

Hardware Complexity

  • default cost model
  • default area model

Software Complexity

  • tech level (number of unique commands used)
  • code volume (total number of bytecodes)

Hardware cost and Software tech level are related, because both penalize the introduction and use of the more sophisticated tools (pistons and then tracks). Hardware area and code volume and related, because both represent how "tightly wrapped" or self contained your project is.

Adding the software metrics generates interesting gameplay. Players are encouraged to create components with similar behavior, so that they can share code between components. Players are encourage to find patterns, to allow refactoring. There is a two-way feedback loop between tweaking the physical layout, and tweaking the software layout. Stuff shows up like "hey, if I made this area more symmetric I could reuse this piston code."

Opus Magnum ByteCode

First bit signals

If the first bit is 0, the byte represents an object. If the first bit is 1, then the byte represents a function.

0 111-1111
  int-!cmd
1 1-111111 
  ?-fncode

Items

All items have both an int and a command. The command is repeated int times. For example (item 6 +turn) will run 6 times.

ints

The int is simply the first three bits as a binary number, between 0 and 5.

A value of 0 indicates that the command will be run 0 times, i.e. skipped entirely without wasting a cycle.

When adding and subtracting these ints, all values rollover at 6. This means that adding three twice wraps you around to your original starting value, as does adding two thrice. This should make it easier to work with spinner arms.

cmds

Commands are indicated by the last four bits. The fourth to last bit indicates the parity of the command; all commands have both negative and positive versions. The "tech level" metric measures how many unqiue commands your project uses. Parities (except on wait and null) count seperately, and so the maximum tech level is 14.

last three bits command positive negative
001 twist Q E
010 turn A D
011 reach W S
100 slide G T
101 hold F R
110 PARAM regular negated
111 wait forward backward
000 null forward backward

can refer to commands as

  • +turn for A (left turn)
  • -turn for D (right turn)
  • +hold for F (fetch)
  • -hold for R (release)

param is for use in functions

null is the standard blank tile, and does nothing. Nulls must be manually included, you can have offset buffering or even no buffering. Extra nulls at the beggining perform the same role as they currently do - "wait through this, then start your loop".

A negative null at the beggining pushes back all other programs. For all other purposes, the parity of null has no effect. As this is purely a conveniance feature, null parity has no effect on tech level.

Waits are similar to nulls, except they skip an entire round (e.g. wait for all machines to read through their buffers). This can help cordinate startup with spinny hexagons, and hopefully allow some new creative solutions. Negative waits push back all other threads, ie let the current thread get setup first.

Functions

The first bit decides whether ("call" or "define"), the remaining 6 bits are the identifier. This means you get 64 functions per project, though some pre-built functions are included.

param

Refering to (item _ param) in a function definition means that when called, that item will be replaced by the parameter. The number field is the number of times the param should be substitutued. The param is substituted with its int field intact.

Here is an example of a user defined macro for multiplication

(define repeat_five) (item 5 +param)

then

(call repeat_five) (item 5 +null)

expands inline to

(item 5 +null) (item 5 +null) (item 5 +null) (item 5 +null) (item 5 +null)

and stalls for 25 whole cycles.

example

So for example a setup with four simple transfer arms

BEFORE (18 code volume, tech level 5)

		(item 1 +hold) (item 1 +turn) (item 1 -hold) (item 1 -turn)
(item 2 +null)  (item 1 +hold) (item 1 -turn) (item 1 -hold) (item 1 +turn)
		(item 1 +hold) (item 1 +turn) (item 1 -hold) (item 1 -turn)
(item 2 +null)  (item 1 +hold) (item 1 -turn) (item 1 -hold) (item 1 +turn)

AFTER (15 code volume, tech level 7)

(define transfer) (item 1 +hold) (item 1 +param) (item 1 -hold) (item 1 -param)

               (call transfer) (item 1 +turn)
(item 2 +null) (call transfer) (item 1 -turn)
               (call transfer) (item 1 +turn)
(item 2 +null) (call transfer) (item 1 -turn)

built in functions

There is functionality that cannot be implemented with the base system, such as int arithmetic and functions with multiple parameters. As I study different scenarios, I hope to identify clean implementations for necesarry building blocks.

These functions will be mapped on some subset of availible function codes. They will be called with (call fname) and can be ovewritten if a user specifies their binary address outside of the normal auto-increment order (define 000010:myFunc) ....

@DylanDmitri
Copy link
Author

The number in the item code should indicate which param it is, not the number of repeats.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment