CTKEngine 1.0.1

dotnet add package CTKEngine --version 1.0.1
                    
NuGet\Install-Package CTKEngine -Version 1.0.1
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="CTKEngine" Version="1.0.1" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="CTKEngine" Version="1.0.1" />
                    
Directory.Packages.props
<PackageReference Include="CTKEngine" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add CTKEngine --version 1.0.1
                    
#r "nuget: CTKEngine, 1.0.1"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package CTKEngine@1.0.1
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=CTKEngine&version=1.0.1
                    
Install as a Cake Addin
#tool nuget:?package=CTKEngine&version=1.0.1
                    
Install as a Cake Tool

NuGet repository

WHAT IS CLETKI

CHETKI is an easy-to-use engine for creating cellular automata. (i.e simplifies automata creation) with multithreading support (CLETKI uses all machine cores by default). It doesn't provides rendering stuff and other things, but you can see an example of making Game of Life simulation and its rendering in the CTKTest project.

FAST HELLO WORLD EXAMPLE WITHOUT EXPLANATION

This code shows how to make GoL simulation and render it:

    internal class Renderer
    {
        // We support only 4 types, ok?
        Dictionary<Cell, char> Type2Symbol = new()
        {
            // REMEMBER: FIRST 2 TYPES (0 AND 1) ARE RESERVER FOR CLETKI'S PURPOSES.
            // ACTUALLY WE SHOULD'NT USE RAW NUMBERS AND PASS TYPES TO THE RENDERER FROM THE CONSTRUCTOR BUT I'M LAZY
            { new Cell() {Type = 2}, '!' },
            { new Cell() {Type = 3}, '%' },
        };

        public void Update(Field field)
        {
            (int, int) start = field.MyBounds.ValidStart;
            (int, int) end = field.MyBounds.ValidEnd;

            for(int y = start.Item2; y < end.Item2; y++)
            {
                for (int x = start.Item1; x < end.Item1; x++)
                {
                    Console.Write(Type2Symbol[field.Map[x, y]]);
                }

                Console.WriteLine();
            }

            Console.WriteLine();
            Console.SetCursorPosition(0, 0);
        }
    }

    static void Main(string[] args)
    {
        int sizeX = 96, sizeY = 48;

        Renderer renderer = new();

        // CellTypeRegistrar.Register() makes an instance of Cell that has a new type and ensures the new type is correct
        Cell dead = CellTypeRegistrar.Register();
        Cell alive = CellTypeRegistrar.Register();

        // Random wrapper calls wrapped rule in [chance] cases of all
        // Here, wrapper calls AlwaysRule in 25 cases of 100
        RandomWrapperRule<AlwaysRule> spawnAliveRule = new(0.25f, new AlwaysRule(alive));
        AutomatonStage randomStage = new(1, spawnAliveRule);

        // Start type wrapper calls wrapped rule when updated cell has start type
        // Here, wrapper calls NearRule when current cell is dead
        // Usually, you will wrap your rules with this wrapper (because you describe rules for specific types like here
        StartTypeWrapperRule<NearRule> birthRule = new(dead, new(alive, alive, 3));

        // Alive cells stay being alive when there's 2 or 3 neighbors,
        // the long list of numbers is "reversed" 2, 3 list because we want to affect cells that "should be changed*
        StartTypeWrapperRule<NearRule> dieRule = new(alive, new( alive, dead, 0, 1, 4, 5, 6, 7, 8));

        AutomatonStage golUpdateStage = new(int.MaxValue, birthRule, dieRule);

        Queue<IAutomatonStage> stages = [];
        stages.Enqueue(randomStage);
        stages.Enqueue(golUpdateStage);

        // First argument is resolution of the simulation field, second is the start type, third is stages of the automaton
        CTKEngine engine = new((sizeX, sizeY), dead, stages);
        while(engine.CanUpdate())
        {
            engine.Update();
            // Renderer is very slow, CLETKI itself is MUCH faster
            renderer.Update(engine.GetState());
        }
    }

EXPLANATION OF CLETKI:

ICellularEngine -- the simulation engine. Consider it as a game-loop. Default implementation is CTKEngine class. Every simulation is consists of a queue of IAutomatonStage<br><br> IAutomatonStage -- a stage of the automaton. Default implementation is the AutomatonStage class. Imagine, you are making a GoL simulation. It consists of 2 stages:

  • Spawn random alive cells in a field of dead ones (do once) -- new AutomatonStage(1, IRule[] weTalkLaterAboutRules)
  • Apply B3/S23 rules for each cell (do as many times as you want, lets say 9999) -- new AutomatonStage(9999, IRule[] ditto) <a/>

IRule -- an action executed on the map if a condition is executed on the map. For example, AlwaysRule(alive) will ALWAYS change cell to alive type and NearRule(always, always, 3) will change the cell to alive type if it has 3 alive neighbors<br><br> Wrappers: <p>in the IRule section I didn't mention randomness or start type of the cell. You can add them using RandomWrapperRule<T>(float chance, T ruleThatShouldHaveRandomChanceToExecute) and StartTypeWrapper<T>(Cell startType, T ruleThatShouldBeExecutedIfCellIsStartType).<br>For example, "replace 25% of all cells with alive ones" can be done as RandomWrapperRule<AlwaysRule>(0.25f, new(alive)), "if a dead cell has 3 alive neighbors, make it alive too" is StartTypeWrapper<NearRule>(dead, new(alive, alive, 3)), and "if an alive cell has less than 2, or greater than 3 neighbors, kill it" is StartTypeWrapper<NearRule>(alive, new(alive, dead, 1, 4, 5, 6, 7, 8))</p>

ALL RULES DOCUMENTATION:

Currently, CLETKI has 6 rules in the CTK.Engine.Rules namespace, here are their constructors:

  • AlwaysRule(Cell endType) -- always changes the updating cell to endType
  • GlobalPositionRule((int, int) position, Cell endType) -- changes the cell at position to endType
  • LocalPositionRule((int, int) bias, Cell requiredType, Cell endType) -- changes the cell to endType, if the cell at bias has requiredType. The bias must be in range [-1; 1], probably simulation will crash with IndexOutOfRangeException if you do it (-2; 10) for example.
  • NearRule(Cell requiredType, Cell endType, params byte[] requiredNeighborsCount) changes cell to endType if requiredNeighborsCount contains count of cell's neighbors that have requiredType
  • RandomWrapperRule<T>(float chance, T rule) -- rule that needed to add random chance of executing the wrapped rule
  • StartTypeWrapper<T>(Cell startType, T rule) -- like previous, but for adding start type

Documentation

Currently, all documentation is described in the Readme.md file (this file). The library is pretty small and I hope this file clearly describes how to use it. You can open CTKTest project to see more examples!

How to build:

Open the solution file and build the project

Product Compatible and additional computed target framework versions.
.NET net10.0 is compatible.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
  • net10.0

    • No dependencies.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.0.1 40 6/2/2026
1.0.0 53 6/1/2026

Fixed clipping of the field resolution (e.g using 62x62 game field when resolution is 64x64)