Self-Modifying Spells (Long)

Post your coolest Hexcasting creations here.

New topics are NOT for chatting or asking help, put those in the comments of a post or in a different forum.
User avatar
Snazz
Posts: 8
Joined: Wed Dec 14, 2022 11:34 pm

Self-Modifying Spells (Long)

Post by Snazz »

To start off, I'm gonna be showing off a lot of compiler spells. A Compiler Spell is a spell that is used to produce other spells.
I like to use compiler spells a lot, so I try to make these spells as versatile as I can with as few patterns and meta-eval as possible to maximize utility and portability. You won't see any use of external memory in these spells; no overwriting the ravenmind, no overwriting spell books or foci. This is to keep the spell compilation process versatile.
Most of these spells I was able to reduce the pattern count using 1.19+ patterns and smarter compilation methods. I've been trying to shrink these spells for a few hours. If there is a way to compact any of the compiler spells further, let me know what I missed.

I'm also going to use my iota notation to explain some things. Here's what you need to know
Iotas can be patterns, lists, numbers, or names:
[Numerical Reflection: 15qqqaw 6 qqqwaawdeeeedeaqqqqq <some iota> eeeqwaeawqde]

A name inside of <angle brackets> signifies exactly one iota. A name inside of (round brackets) signifies zero or more iotas, for example,
[qqqaadaaqqd (Create Particle Star Spell) eeeqqqaw [(Vector List)] dadad]


I use a similar input/output notation as the hex book:
<second top iota on the stack>, <top iota on the stack> -> <output to the second top of the stack>, <output to the top of the stack>

I made my compiler spells expect the stack to be in an intuitive order. If a spell is taken as input, the stack should generally be arranged in a way where just drawing Hermes Gambit would cause the spell to evaluate normally, and not throw any errors.

________________________________________________________________________________________________________________________________________________________________________________


So we want to make a self modifying spell, lets tackle the modifying part first without worrying about replication for now. An easy place to start is with Stygian Weave spells (Stygian spells). These are spells that are meant to be duplicated before they are cast. There are a couple reasons a spell may want to be cast like this, but the main one is for storing data. The copy of the spell dissects the original to obtain raw data that has been embedded.

An easy way to create Stygian spells is with Charon's Gambit. The Charon pattern halts spell execution. That means that you can end a spell pattern list with a Charon, then append raw data directly afterwards without causing the spell to throw errors when cast.

I discovered a nice design pattern for these spells. A post-Charon list is extracted, then that list is unpacked and the first iota is executed with Hermes Gambit. The idea here is that when the list is unpacked, it will leave the stack with the spell you want to cast (called the function spell) at the top, and the other elements (the arguments) will make up the rest of the stack. When the function spell is executed, it can access all of the argument iotas.

[Numerical Reflection: 5deeedqwaeawqdeaqqaqdee [(arguments), [(function spell)]]]


I streamlined the creation of this spell design with Stygian Loom. It takes a spell with any number of raw arguments and turns them into a Stygian spell.

Stygian Loom (13 patterns)
(arguments), [(function spell)] -> [(spell)]

Code: Select all

{
    Flock's Reflection
    Flock's Gambit
    {
        Numerical Reflection: 5
        Selection Distillation
        Flock's Disintegration
        Hermes' Gambit
        Charon's Gambit
    }
    Jester's Gambit
    Combination Distillation
}


For our purposes, instead of extracting data from the spell copy, we want a spell that can modify the copy to achieve different behaviors between castings. I call this type of spell a Royal Stygian Weave, or just a Royal Spell. It's defining feature is that it leaves behind a modified version of itself (a new Royal spell) on the stack when cast as a Stygian.

Royal spells are tricky to construct though, we can't just make a spell that changes large parts of itself at random because at the end it needs to compile into another Royal Stygian for the next cast. We need to be careful about what parts of the spell we modify.

Lets construct such a spell using the same approach that we used for Stygian Weaves. The overall layout is a base spell followed by a Charon. After the Charon, we place all the variable argument iotas. The base spell will unpack the arguments, cast the function spell, then recompile the new arguments into a new Royal spell.

[qwaeawq (function spell) qwaeawqaeaqaewdqdweaqdee (arguments)]


I made a compiler to streamline the process. This takes a function spell and variable arguments and turns them into a Royal Spell.
Royal Loom (20 patterns)
(arguments), [(function spell)] -> [(spell)]

Code: Select all

{
    Flock's Reflection
    Flock's Gambit
    Retrograde Purification
    Speaker's Decomposition
    {
        Flock's Disintegration
    }
    Jester's Gambit
    {
        Flock's Reflection
        Flock's Gambit
        Charon's Gambit
    }
    Combination Distillation
    Combination Distillation
    Jester's Gambit
    Retrograde Purification
    Combination Distillation
}
I was not satisfied with this form of Royal Spell. It can't easily use external arguments from the stack because the stack is dirty with the spell's pattern iotas, and it cannot leave any iotas behind on the stack other than itself. Everything gets sucked up with Flock's Gambit.

I made another compiler spell called Royal Loom + that fixes these issues by only using one iota for the argument. If a spell requires multiple arguments, the iota can be a list of arguments. (This will be helpful later)

Royal Loom + (28 patterns)
<argument>, [(function spell)] -> [spell]

Code: Select all

{
    // append consideration to the end of the function spell
    Consideration
    Consideration
    Consideration
    Consideration
    Integration Distillation

    {
        // reverse the spell list, pop the arg
        Retrograde Purification
        Speaker's Decomposition
        
        // get the function spell
        Prospector's Gambit
        Numerical Reflection: 0
        Selection Distillation
        
        // add the base spell list (escaped) to the end
        Rotation Gambit
        Retrograde Purification
        Integration Distillation
        
        // patterns to add the arg back onto the base spell
        {
            Jester's Gambit
            Integration Distillation
        }
        Combination Distillation
        
        // cast the compiled spell
        Hermes' Gambit
        
        // halt casting before args
        Charon's Gambit
    }
    
    // append the function spell and arg after the charon
    Jester's Gambit
    Integration Distillation
    Jester's Gambit
    Integration Distillation
}
________________________________________________________________________________________________________________________________________________________________________________


Now that we have solved the issue of modification, lets figure out self replication. For this, we need to turn to Quines. In computer science, a Quine is a program that outputs itself. For hexcasting, a Quine is a spell that leaves itself on the stack when executed with Hermes' Gambit.

Here is a simple Quine, It works by nesting itself every time it's cast.

[qqqaw [qqqaw <placeholder> Numerical Reflection: 1aaeddwqaeaqw] Numerical Reflection: 1aaeddwqaeaqw]

You can think of this spell as having two states, there is the base state that holds the placeholder (which can be any iota) after the consideration, and there is the single nested state, which holds the base state spell instead of the placeholder.
When cast, the single nested state spell puts the base state spell onto the stack, then copies it and inserts it into the other base state spell at the position of the placeholder, thus turning it into the single nested state.


Basic Quine Compiler (11 patterns)
-> [(spell)]

Code: Select all

{
    Consideration
    Consideration
    Bookkeeper's Gambit: -  //placeholder iota
    Numerical Reflection: 1
    Prospector's Gambit
    Surgeon's Exaltation
}
Numerical Reflection: 1
Prospector's Gambit
Surgeon's Exaltation

It's trivial to add extra patterns by appending them to the end of the base spell, these will be executed after the spell has copied itself so we can do some pretty interesting things here.
The first that comes to mind is making what I like to call a Hydra Quine. A spell that, when executed, returns two copies of itself to the stack.

[qqqaw [(base spell)] Numerical Reflection: 1aaeddwqaeaqwaadaa]


This is accomplished simply by appending a Gemini Decomposition to the end of the base spell when we are constructing it.
Hydra Quine Compiler (12 patterns)
-> [(spell)]

Code: Select all

{
    Consideration
    Consideration
    Bookkeeper's Gambit: -
    Numerical Reflection: 1
    Prospector's Gambit
    Surgeon's Exaltation
    Gemini Decomposition
}
Numerical Reflection: 1
Prospector's Gambit
Surgeon's Exaltation

we can attach basically anything we want at the end of the quine, but it's a bit annoying that we have to deal with having a dirty stack when whatever spell is at the end gets cast. If we want a spell to execute before the quine copies itself, we need to move this function spell to the beginning of the quine. This proves tricky as the variable length of a function spell at the beginning throws off the insertion index.

There are three main methods we can use to avoid this:
1. reverse the quine so the distance to the insertion index is from the back of the spell list rather than the front, then insert, and reverse again
2. use an escaped pattern list for the function spell and execute it with Hermes to achieve a constant length spell
3. find the length of the function spell and add it as an offset for the insertion index


Using the first method, we get something like this:
[(function spell) qqqaw [(base spell)] qqqaedeNumerical Reflection: 6aaeddqqqaedewqaeaqwqqqaede]

The Queen Quine compiler takes any spell, and inserts it into a quine of this format.
Queen Quine (18 patterns)
[(function spell)] -> [(spell)]

Code: Select all

{
    // append a consideration to the end of the funciton spell
    Consideration
    Consideration
    Consideration
    Consideration
    Integration Distillation

    // create the insertion pattern list
    {
        Combination Distillation // placeholder
        Retrograde Purification
        Numerical Reflection: 6
        Prospector's Gambit
        Retrograde Purification
        Surgeon's Exaltation
        Retrograde Purification
    }

    // use the insertion pattern list to append itself, then nest the quine
    Gemini Decomposition
    Hermes' Gambit
}

If we look at the second method though, it's clear that this will work very easily with Stygian spells. We're already using a pattern list and Hermes, so all we need to do is to duplicate the spell pattern list before we execute it. We could even use a Royal spell for the function spell and insert its output into the base spell when nesting the Quine to get a self modifying spell!

[qqqaw [(royal spell)] aadaadeaqqqqqaw [(base spell)] Numerical Reflection: 5aaeddwqaeaqwNumerical Reflection: 1aaeaawqaeaqw]


The King Quine compiler uses this method to incorporate a Royal spell into a Quine. After the Royal has been executed, the output is used to overwrite the function spell placeholder in the base spell. So the next time the quine is cast, it executes the new Royal.
King Quine (27 patterns)
[(royal spell)] -> [(spell)]

Code: Select all

{
    {
        // put the Royal spell on the stack
        Consideration
        Consideration
        Consideration
        Consideration
        Bookkeeper's Gambit: - // function spell placeholder

        // cast as Stygian
        Gemini Decomposition
        Hermes' Gambit

        // put the Base spell on the stack
        Consideration
        Consideration
        Consideration
        Consideration
        Bookkeeper's Gambit: - // base spell placeholder
        
        // duplicate base, and insert into copy
        Numerical Reflection: 5
        Prospector's Gambit
        Surgeon's Exaltation

        // insert result of Royal Stygian
        Numerical Reflection: 1
        Rotation Gambit
        Surgeon's Exaltation
    }
    
    // copy the injection patterns, and execute them
    Gemini Gambit
    Numerical Reflection: 6
    Numerical Reflection: 12
    Selection Exaltation
    Hermes' Gambit
}
(Just make sure that you are using Royal Loom +, and not Royal Loom to produce the Royal Stygian if you want to preserve anything on the stack when you cast the Quine)

Finally we have it, a spell that modifies itself when it is cast and can change it's own functionality. But we can make it much better with a small modification. Remember the Hydra Quine? It's not possible to produce such a spell with the current King Quine compiler. The Royal Spell is executed before the replication process. However, we can add a section after the replication patterns in the base spell called the Meta spell, which is used to manipulate the produced Quine.

[qqqaw [(royal spell)] aadaadeaqqqqqaw [(base spell)] Numerical Reflection: 5aaeddwqaeaqwNumerical Reflection: 1aaeaawqaeaqw (meta spell)]

We can implement this into the compiler trivially by adding two patterns
King Quine + (29 patterns)
[(royal spell)], [(meta spell)] -> [(spell)]

Code: Select all

{
    {
        // put the Royal spell on the stack
        Consideration
        Consideration
        Consideration
        Consideration
        Bookkeeper's Gambit: - // function spell placeholder

        // cast as Stygian
        Gemini Decomposition
        Hermes' Gambit

        // put the Base spell on the stack
        Consideration
        Consideration
        Consideration
        Consideration
        Bookkeeper's Gambit: - // base spell placeholder

        // duplicate base, and insert into copy
        Numerical Reflection: 5
        Prospector's Gambit
        Surgeon's Exaltation

        // insert result of Royal Stygian
        Numerical Reflection: 1
        Rotation Gambit
        Surgeon's Exaltation
    }

    // add meta spell onto the end of the base spell
    Jester's Gambit
    Combination Distillation

    // copy the injection patterns, and execute them
    Gemini Gambit
    Numerical Reflection: 6
    Numerical Reflection: 12
    Selection Exaltation
    Hermes' Gambit
}

To show off what we can do with these new compilers, lets make a spell that counts how many times it has been cast, then deletes itself when it has been cast for the 5th time.
First we need to create the variable argument. Lets start with 0. Next, we need to create a spell that increments the number on the stack, reveals it, and leaves 'true' on the stack if the number reaches 5. At the end of this spell, the the number should be left above the boolean on the stack, the number will get sucked up as the arg for the next casting of the royal spell, and the bool will stay on the stack until the meta spell is evaluated.
[Numerical Reflection: 1waawdeaadaaNumerical Reflection: 5adaawdd]
0


After this, use scribe's reflection to put Royal Loom + on the stack, then execute it with Hermes. We are now left with the Royal Spell. Now we want to add the meta spell. It will take the boolean on the stack, and drop the current spell list if the boolean is true:
[aawddqqqawBookkeeper's Gambit: Drop 1qqqawBookkeeper's Gambit: Keep 1awdddeaqq]
[
(royal spell)]


Next, use scribe's reflection to put King Quine + on the stack, and execute with Hermes. The resulting quine counts how many times it has been cast, and deletes itself when it has been cast for the 5th time.
You can use the meta spell to do all sorts of interesting things, such as recasting the quine until some condition is met, switching out the function spell, filling every page in your spell book with a copy of itself (okay, maybe don't do that one)


This does feel a bit clunky though, We have to use two compiler spells to produce just one Quine. Its 28+29=57 patterns worth of compiler spells and the compiled spell uses up a meta-evaluation unnecessarily. The process can be streamlined by merging Royal Loom + and King Quine +.
Because we don't want to use any meta-evaluations, there can be variable length patterns before (the function spell) and after (the meta spell) the escaped base spell list. So we need to use the 3rd nesting method: find the length of the function spell and add it as an offset for the insertion index.

[qqqaw <arg> (func spell) qqqaw [(base spell)] qqqaw <base index> aaeddwqaeaqwNumerical Reflection: 1aaeaawqaeaqw (meta spell)]

King's Loom (33 patterns)
<argument>, [(function spell)], [(meta spell)] -> [(spell)]

Code: Select all

{
    Jester's Gambit
    Consideration
    Consideration
    Consideration
    Consideration
    Single's Purification

    Undertaker's Gambit
    Nullary Reflection
    Integration Distillation

    Undertaker's Gambit
    Combination Distillation
    Combination Distillation

    Undertaker's Gambit
    Abacus Purification
    Numerical Reflection: 1
    Subtractive Distillation
    Integration Distillation

    {
        Prospector's Gambit
        Surgeon's Exaltation
        Numerical Reflection: 1
        Rotation Gambit
        Surgeon's Exaltation
    }
    Combination Distillation
    Undertaker's Gambit
    Combination Distillation

    Rotation Gambit
    Combination Distillation

    Jester's Gambit
    Hermes' Gambit
}

And there we have it, A single spell that can compile any type of self modifying spell.

________________________________________________________________________________________________________________________________________________________________________________


Alright, now I've talked all about Stygian Weave, Royals, and Quines, but what we have right now isn't actually very practical. The main issue is the lifecycle of a Quine. The Quine lives on the stack, and as soon as we clear the pattern grid, it'll disappear.

The solution to this is to save the quine to an external storage with the meta spell. If you choose to use a focus or spellbook, then the meta spell should check if it can write to the item in the offhand, and save itself if it can.

[(King's Loom)]
[
deeeeeqqqqawdeeeeeqqqawBookkeeper's Gambit: Keep 1awdddeaqq]
[
(func spell)]
<arg>

(then use hermes' gambit to compile the spell, and save it to a focus or spellbook)


Using this even allows you to cast the spell with a standard CAD!
A dynamic quine that can live on the stack or in an item is rather powerful. But what if we don't care about it living on the stack, what if we are only going to use our spell in conjunction with a save item?

It turns out that we can cut a lot of corners. The spell doesn't even need to be a quine. We can use scribe's reflection to obtain a copy of the spell rather than having to nest it.

[qqqaw <arg> (func spell) aqqqqqNumerical Reflection: 1aaeaawqaeaqwdeeeee]


This is what the Enlace compiler creates. It's short, simple, and produces high utility spells. Definitely one of my favorite compiler spells.
Enlace (17 patterns)
<argument>, [(function spell)] -> [(spell)]

Code: Select all

{
    Jester's Gambit
    Speaker's Distillation
    Consideration
    Consideration
    Consideration
    Consideration
    Speaker's Distillation
    {
        Scribe's Reflection
        Numerical Reflection: 1
        Rotation Gambit
        Surgeon's Exaltation
        Scribe's Gambit
    }
    Combination Distillation
}
Example:
Switchback
A spell for teleporting between 2 locations.
Cast while standing to teleport to the last place you cast this spell
Cast while sneaking to set your current location as the teleportation destination (without teleporting to the previous location)

Switchback (20 patterns)

Code: Select all

// arg
Mind's Reflection
Compass' Purification

// standing spell
{
    Mind's Reflection
    Compass' Purification
    Undertaker's Gambit
    Subtractive Distillation
    Mind's Reflection
    Jester's Gambit
    Greater Teleport
}

// sneaking spell
{
    Bookkeeper's Gambit: v
    Mind's Reflection
    Compass' Purification
}

// compile everything together
Scribe's Reflection // Knitting Needle
Hermes' Gambit
Scribe's Reflection // Enlace
Hermes' Gambit
________________________________________________________________________________________________________________________________________________________________________________


So what's the next step? How do we take this further?

The answer is Advanced Multitool Spells. A multitool spell is a type of spell that has two or more different tools/spell functions, and a way to choose which one to use. Switchback was a simple multitool with only two possible functions (set location, and tp). An advanced multitool allows you to select a tool, and it will keep track of the selected tool until you select a different one. This type of spell is handy if you don't yet have access to spellbooks but want to keep multiple spells handy for CAD casting.

The construction I'm going with for this multitool is to have the arg be a list containing the currently selected tool index, followed by a bunch of tool spells.
[<tool index> (tool spells)]

If the spell is cast by a sneaking player, it will cycle the index. If the player isn't sneaking, it will grab the spell at the current index and execute it.

Basic Multitool Compiler (24 patterns)
[(list of tool spells)] -> [(spell)]

Code: Select all


// construct the arg, with the initial index of 0
Numerical Reflection: 0
Speaker's Distillation

// selection spell
{
    // add 1 to the index
    Speaker's Decomposition
    Numerical Reflection: 1
    Additive Distillation

    // loop the limit
    Prospector's Gambit
    Abacus Purification
    Modulus Distillation
    
    // print new index
    Reveal

    // replace the arg
    Speaker's Distillation
}

// casting spell
{
    // cast the selected spell
    Speaker's Decomposition
    Selection Distillation
    Hermes' Gambit

    // restore the arg
    Scribe's Reflection
    Numerical Reflection: 1
    Selection Distillation
}

// compile everything
Scribe's Reflection (Knitting Needle)
Hermes' Gambit
Scribe's Reflection (Enlace)
Hermes' Gambit
I like this format because it's really customizable, you can switch out the selection spell for a different one, or you could change the casting spell to cast everything as a Stygian spell. Probably my favorite thing about this format is that it supports Meta Tool spells - the tool spells themselves can modify the arg!

As an example, A simple meta tool may execute a levitation spell, then set the multitool index to the index of an impulse spell.

A very handy meta tool I like to use is New Page. It takes a spell on the stack, and adds it to the multitool.

New Page (11 patterns)
[(tool spell)] ->

Code: Select all

{
    // get the metatool spell list
    Scribe's Reflection
    Undertaker's Gambit

    // get the argument
    Numerical Reflection: 1
    Undertaker's Gambit
    Selection Distillation

    // add the new spell to the argument
    Rotation Gambit
    Integration Distillation

    // save the new argument to the spell and save the new spell to the item in the offhand
    Surgeon's Exaltation
    Scribe's Gambit
}
________________________________________________________________________________________________________________________________________________________________________________




Thanks for reading! :D I've been working on this for several days. If you have any questions or want to show off your own self-modifying spells, leave a reply!

Also, I didn't explicitly state this above, but the compilers you should be focusing on for making self-modifying spells are King's Loom for quines and Enlace for focus/spellbook spells.