Search Results for

    Show / Hide Table of Contents

    Model Reference: Oracle Method

    In the fully synchronous activation model, each amoebot is activated once in every round and has only a local view of the system. Some algorithms require global planning or coordination which is made possible by using oracle methods.

    Oracle calls can be reused and nested by implementig Suboracle classes.

    Creating Custom Oracle Methods

    An oracle method is a static method that has the following properties:

    • The method is defined by a ParticleAlgorithm subclass, i.e., it must belong to an algorithm
    • It must have exactly one parameter: A ParticleSystem, providing access to the entire structure of amoebots
    • It must return a bool value and return true if the algorithm has finished
    • It must be marked with the Oracle attribute so that the simulator recognizes the method and calls it during the simulation round

    Oracle methods are called automatically by the simulator before the movement phase of each round. All particles are set to be active during the method call, so attributes of other amoebots can be accessed and movements can be planned.

    The following example shows the pattern for creating a status info method:

    public class MyAlgorithm : ParticleAlgorithm {
        ...
        [Oracle]
        public static bool MyOracle(AS2.Sim.ParticleSystem system) {
            // Implement custom oracle here
            foreach (Particle p in system.particles)
            {
                p.algorithm.Expand();
            }
            return true;
        }
        ...
    }
    

    Implementing Suboracles

    Similar to subroutines, Suboracle classes can be used to encapsulate and nest subtasks on a group of member particles. Each member particle owns its own suboracle instance (created in the particle constructor) that stores per-particle state via ̀ParticleAttribute attributes. One designated member — the representative — drives the subtask: its Init(List<T> memberParticles) method receives the full member list and its Activate() method is called round-by-round until the subtask completes, either by an oracle method on the owning ParticleAlgorithm or inside another suboracle. A suboracle instance on a representative can be reused, but needs to be resetted via Reset() before re-initialisation.

    public class MySuboracle : Suboracle<MySuboracle>
    {
        ParticleAttribute<int> myAttribute;
        ParticleAttribute<int> memberAttribute;
        ...
        public MySuboracle(Particle rep) : base(rep)
        {
            myAttribute = representative.CreateAttributeInt(FindValidAttributeName("[MySuboracle] myAttribute"), 0);
            memberAttribute = representative.CreateAttributeInt(FindValidAttributeName("[MySuboracle] memberAttribute"), 0);
            ...
        }
    
        public void Init(List<MySuboracle> memberParticles, bool attribute)
        {
            base.Init(memberParticles);
    
            myAttribute.SetValue(attribute);
    
            memberParticles.ForEach(p => p.memberAttribute.SetValue(attribute))
            ...
        }
    
        protected override bool OnActivate()
        {
            if (myAttribute.GetCurrentValue() == 0)
            {
                ParticleAlgorithm[][] grid = MemberGrid();
    
                for (int y = 0; y < grid.Length; y++) // local coordinates
                {
                    for (int x = 0; x < grid[y].Length; x++)
                    {
                        ParticleAlgorithm p = grid[y][x];
                        if (p != null && GetMember(p).memberAttribute.GetCurrentValue() == 0)
                        {
                            p.Expand();
                        }
                }
            }
            ...
    
            return false;
        }
    
        ...
    }
    
    public class MyAlgorithm : ParticleAlgorithm {
        ...
        MySuboracle mySuboracle;
        ...
        public MyAlgorithm(Particle p) : base(p)
        {
            ...
            mySuboracle = new MySuboracle(p);
            ...
        }
        ...
        [Oracle]
        public static bool MyOracle(AS2.Sim.ParticleSystem system) {
            if (round.GetCurrentValue() == 0) {
                List<MySuboracle> members = new List<MySuboracle>();
                members.Add(system.particles[0].algorithm.mySuboracle);
                members.Add(system.particles[1].algorithm.mySuboracle);
                members.Add(system.particles[2].algorithm.mySuboracle);
    
                system.particles[0].algorithm.mySuboracle.Init(members, 42); // the first particle is acting as the representative
    
                // Alternatively, a list of ParticleAlgorithms can be mapped to their suboracle instances:
                List<MySuboracle> members2 = new List<MySuboracle>();
                members2.Add(system.particles[3].algorithm);
                members2.Add(system.particles[4].algorithm);
                members2.Add(system.particles[5].algorithm);
                system.particles[3].algorithm.mySuboracle.Init(GetSuboracles(members2, p => p.mySuboracle), 23);
            }
            else {
                system.particles[0].algorithm.mySuboracle.Activate();
            }
            ...
        }
        ...
    }
    

    Member Grid

    The MemberGrid(Direction yAxis, Direction xAxis, bool includeTail) method of a suboracle instance builds a 2D grid (array of arrays) of all member particles, projected onto a custom local coordinate system defined by two axes.

    The grid is built by projecting each member particle's head position onto a custom coordinate system. By default, the y-axis is NNE and the x-axis is yAxis.Rotate60(-1) (one step clockwise):

    The returned grid is a ParticleAlgorithm[][] where:

    • Attention: The first index is the y-coordinate (row), the second is the x-coordinate (column): grid[y][x].
    • Each cell contains the ParticleAlgorithm of the member particle whose head occupies that position, or null if the cell does not contain a head.
    • The grid's origin (index [0][0]) is automatically shifted so that the minimum x- and y-coordinates among all member particles map to index 0.

    If includeTail is set to true, each member particle is also placed in the cell occupied by its tail.

    Since the grid stores ParticleAlgorithm references, you can retrieve the corresponding suboracle instance using GetMember(ParticleAlgorithm p):

    ParticleAlgorithm[][] grid = MemberGrid();
    
    for (int y = 0; y < grid.Length; y++)
    {
        for (int x = 0; x < grid[y].Length; x++)
        {
            ParticleAlgorithm p = grid[y][x];
            if (p != null)
            {
                MySuboracle member = GetMember(p);
                // ... operate on member ...
            }
        }
    }
    

    Member grid

    The GetGridPos(ParticleAlgorithm[][] memberGrid) method searches a previously built member grid for the coordinates containing the particle that it is called on.

    • Edit this page
    In this article
    Back to top AmoebotSim 2.0 Documentation v1.12
    Copyright © 2025 AmoebotSim 2.0 Authors
    Generated by DocFX