A world is a mind

  • 16 Replies
  • 552 Views
*

Zero

  • Trusty Member
  • **********
  • Millennium Man
  • *
  • 1198
  • Qu'aurai-je la satisfaction d'avoir accompli ?
A world is a mind
« on: December 17, 2021, 07:30:01 pm »
Hi old friends,

I hope you're fine, in good health and feeling good. I wish you a nice end of year.
 :)

I propose:


Don't try to create a mind. That's impossible.
Instead, only try to build an entire world.
Then you'll realize that, this world is a mind.


What do you think?
We're not something that is changing. We are the change of something.

*

infurl

  • Administrator
  • ***********
  • Eve
  • *
  • 1298
  • Humans will disappoint you.
    • Home Page
Re: A world is a mind
« Reply #1 on: December 18, 2021, 01:12:29 am »
You could subscribe to the Gaia hypothesis I suppose but I don't personally.

https://en.wikipedia.org/wiki/Gaia_hypothesis

I have no doubt that life and non-life have been intimately connected for as long as the Earth has existed, and possibly even longer than that if there is anything to Panspermia.

https://en.wikipedia.org/wiki/Panspermia

However the Free Energy Principle makes a very clear distinction between the processes of life and non-life and it now has a huge body of empirical evidence to support it.

https://en.wikipedia.org/wiki/Free_energy_principle

Nevertheless, the idea that the Earth itself could be a mind has been explored pretty thoroughly in David Brin's excellent novel of that name and I highly recommend reading it.

https://en.wikipedia.org/wiki/Earth_(Brin_novel)

I'm sorry it doesn't seem to be available in French though.

https://www.amazon.com/Earth-David-Brin/dp/055329024X/

I wish for you all the very best too. Your contributions here are highly valued.

*

Zero

  • Trusty Member
  • **********
  • Millennium Man
  • *
  • 1198
  • Qu'aurai-je la satisfaction d'avoir accompli ?
Re: A world is a mind
« Reply #2 on: December 18, 2021, 10:16:02 am »
I didn't know about the Free Energy Principle, thanks for the pointer :)
It's a very clever way of seeing things indeed.

Implementing a world seems impossible at first. For anything in a world, any entity we can distinguish, is actually made of components, which themselves are made of components, and so on. I'm not specifically talking about atoms and molecules here, you can also see it differently. In a sheet of paper, there's a tree, because without the tree you can't make the paste for the paper. The sheet of paper is also made of sunshine, because without the sunshine and the rain, the tree cannot grow. If you take the rain out of the sheet of paper, there's no sheet of paper. In 1 entity, there's the entire world.

If you go the Entity-Component-Systems (ECS) road, it would mean that components are themselves entities. So it would probably be best emulated with a sort of directed-graph-systems approach, where nodes are both potentially entities and components, and edges encode the compound-component relations.

We're not something that is changing. We are the change of something.

*

MagnusWootton

  • Starship Trooper
  • *******
  • 354
Re: A world is a mind
« Reply #3 on: December 18, 2021, 10:25:58 am »
Hi old friends,

I hope you're fine, in good health and feeling good. I wish you a nice end of year.
 :)

I propose:


Don't try to create a mind. That's impossible.
Instead, only try to build an entire world.
Then you'll realize that, this world is a mind.


What do you think?


If you create a universe, or a mind,  it doesn't matter either way because they are the same thing.  (LOTS OF COMPUTATIONS!! :))

Solving one would solve the other tho, I agree.  (If thats what you meant OC.)

*

Zero

  • Trusty Member
  • **********
  • Millennium Man
  • *
  • 1198
  • Qu'aurai-je la satisfaction d'avoir accompli ?
Re: A world is a mind
« Reply #4 on: December 18, 2021, 04:03:27 pm »
I happen to be working on a roguelike. Very relaxing by the way... Hence the post.

But what good is an AiDreamer's dream without its companion code snippet?

 ::)  If you know me, you knew it was coming, so here it is: 200 locs of 4-hours phone-written untested casual Javascript. I think we can safely run it without triggering the singularity!
  ;D

Code: javascript


function World(opt = {}) {
   
    this.systems = opt.systems || [];
    this.things = opt.things || {};
    this.cutRequests = [];
    this.delRequests = [];
   
    // every thing will be part of the whole
    this.whole = this.thing();
}



World.prototype.genId = (function() {
    let id = 0n;
    return function(prefix) {
        return prefix + (id++);
    }
})();



World.prototype.partof = function(compoundId, componentId) {

    // getter: get things which are part of argument 1
    if (!componentId) return this.things[compoundId].madeof;

    // setter: attach a new component to argument 1
    this.things[compoundId].madeof.push(componentId);
    this.things[componentId].partof.push(compoundId);
}



World.prototype.madeof = function(componentId, compoundId) {

    // getter: get things which are made of argument 1
    if (!compoundId) return this.things[componentId].partof;

    // setter: attach argument 1 to a new compound
    this.things[compoundId].madeof.push(componentId);
    this.things[componentId].partof.push(compoundId);
}



World.prototype.thing = function(t = {}, edges) {
   
    // getter version
    if (typeof t == "string")
        return this.things[t.toString()];
   
    // setter version
    let id = this.genId('T');
    this.things[id] = {
        value: t,
        next: null,
        partof: [],
        madeof: []
    };
   
    // always part of the whole
    if (this.things[this.whole])
        this.madeof(this.whole, id);
   
    // edges can be set up at creation
    // things they link must already exist
    if (edges) {
        if (edges.partof)
            for (let compoundId of edges.partof)
                this.madeof(id, compoundId);
        if (edges.madeof)
            for (let componentId of edges.madeof)
                this.partof(id, componentId);
    }
    return id;
}



World.prototype.cut = function(tid1, tid2) {
   
    // edge-cuts are not immediate
    // they are requested first
    this.cutRequests.push([tid1, tid2]);
}



World.prototype.cutNow = function(tid1, tid2) {

    // if edges still exist
    if (!((tid1 in this.things) && (tid2 in this.things))) return;

    // tid1 is not part of tid2 anymore
    this.things[tid1].partof =
        this.things[tid1].partof.filter(tid => tid != tid2);

    // tid1 is not made of tid2 anymore
    this.things[tid1].madeof =
        this.things[tid1].madeof.filter(tid => tid != tid2);

    // tid2 is not part of tid1 anymore
    this.things[tid2].partof =
        this.things[tid2].partof.filter(tid => tid != tid1);

    // tid2 is not made of tid1 anymore
    this.things[tid2].madeof =
        this.things[tid2].madeof.filter(tid => tid != tid1);
}



World.prototype.del = function(tid) {
   
    // thing deletions are not immediate
    // they are requested first
    this.delRequests.push(tid);
}



World.prototype.delNow = function(tid) {
   
    // if things still exist
    if (!(tid in this.things)) return;

    // they're not part of anything anymore
    for (let compoundId of this.things[tid].partof)
        this.things[compoundId].madeof =
            this.things[compoundId].madeof.filter(t => t != tid);
       
    // they're not made of anything anymore
    for (let componentId of this.things[tid].madeof)
        this.things[componentId].partof =
            this.things[componentId].partof.filter(t => t != tid);

    delete this.things[tid]
}



World.prototype.system = function(opt) {
   
    let id = this.genId('S');
   
    // systems will run in order of creation
    this.systems.push({
        id,
        // triggers is a list of qualifying functions
        triggers: opt.triggers,
        // template function calculates the next world state
        template: opt.template,
        // systems may be deactivated dynamically
        active: !opt.inhibited
    });
    return id;
}



World.prototype.status = function(sid, active) {
   
    if (arguments.length == 1)
        // toggle
        this.systems[sid].active = !this.systems[sid].active;
   
    else
        // set
        this.systems[sid].active = !!active;

    return this.systems[sid].active;
}



World.prototype.qualify = function(system, thing) {
   
    // each trigger of a system
    // must find at least 1 component
    // that meets its requirements
    for (let trigger of system.triggers) {
        let greenlight = false;
        for (let componentId of thing.madeof)
            if (trigger(this.things[componentId])) {
                greenlight = true;
                break;
            }
        // else the system does not qualify
        if (!greenlight) return false;
    }
    return true;
}



World.prototype.step = function() {
   
    // run systems
    // if they are active
    // and where they qualify
    // to prepare the next world state
    for (let system of this.systems)
        if (system.active)
            for (let tid in this.things)
                if (this.qualify(system, this.things[tid]))
                    this.things[tid].next =
                        system.template(this.things[tid]);
                   
    // apply edge-cut requests
    for (let request of this.cutRequests)
        this.cutNow(request[0], request[1]);
    this.cutRequests = [];

    // apply thing deletion requests
    for (let request of this.delRequests)
        this.delNow(request);
    this.delRequests = [];

    // make the next world state actual
    for (let tid in this.things) {
        if (this.things[tid].next)
            this.things[tid].value = this.things[tid].next();
        this.things[tid].next = null;
    }
}



// ==============================



let w = new World();

let me = w.thing({ who: "me" }, {
    madeof: [
        w.thing({ type: "human" }),
        w.thing({ x: 5, y: 8 })
    ]
})

let testsys = w.system({
    triggers: [
        function(component) {
            return component.value.type == "human";
        }
    ],
    template: function(thing) {
        console.log(thing.value.who);
    }
});

w.step();



Apparently the highlighter doesn't like JS, maybe something I'm doing wrong?

Edit: added usage example
« Last Edit: December 18, 2021, 07:50:32 pm by Zero »
We're not something that is changing. We are the change of something.

*

Zero

  • Trusty Member
  • **********
  • Millennium Man
  • *
  • 1198
  • Qu'aurai-je la satisfaction d'avoir accompli ?
Re: A world is a mind
« Reply #5 on: December 19, 2021, 04:19:11 pm »
The shape of data is good. But there's something wrong with the execution model, I don't like it. I'll try something else. I'd like to handle conflicts, keep looping until every system is happy with the changes to come, and only then, apply the changes.
We're not something that is changing. We are the change of something.

*

WriterOfMinds

  • Trusty Member
  • *******
  • Starship Trooper
  • *
  • 465
    • WriterOfMinds Blog
Re: A world is a mind
« Reply #6 on: December 19, 2021, 10:52:00 pm »
A nice year's end to you too, Zero. And good luck with your roguelike!

*

DaltonG

  • Roomba
  • *
  • 16
Re: A world is a mind
« Reply #7 on: December 20, 2021, 12:52:10 am »
"Don't try to create a mind. That's impossible."

I've seen that said many times before - impossible. Early on, I accepted the notion that the brain/mind was just too complicated to understand and simulate. Eventually, I came to believe that there couldn't be any real intelligence without a mind/body connection (sentience - subjective experience) and this drove me to reconsider if this was true. Eventually my perspective on the subject began to change when I changed my approach. I quit taking it for granted that all the so called experts were right. In criminology they say, "Follow the money," and that gave me the idea that to understand how the brain/mind worked was to Follow the Signal. Things really started to come together when I spent a little time when considering the analogically similar functions of a transistor with the neuron. A simple question set me off on what I now consider a serendipitous path - "What in the world do those neurons have so many connections?" When I finally decided that to refer to the pattern of synapses as a representation of a memory (implying that a single neuron could represent more than one memory) was wrong and that they were selectors. From this came the notion that the synapses were selectors and that the function of the dendritic synapses were influential, not deterministic. My approach changed from being shackled to popular neuroscientific principles to imagining how it had to operate in terms of circuitry. Don't get me wrong, there are a lot of fundamental neuroscience principles that are valid and useful. So much of our present science is guided and influence by the historical past that it drags in the errors, inconsistencies, and the outmoded. I see science papers that are truly ground-braking which fall apart when they try to shoe horn their results to fit principles dredged up from the past. To "Stand on the Shoulder of Giants from the Past also serves to Constrain one's perspectives to the same limited views of the past. The list of citations that accompany papers serve as a testament to this as a fact - it's really just name dropping to give their own papers more credibility.

Merry Christmas and Happy New Year

*

Zero

  • Trusty Member
  • **********
  • Millennium Man
  • *
  • 1198
  • Qu'aurai-je la satisfaction d'avoir accompli ?
Re: A world is a mind
« Reply #8 on: December 20, 2021, 01:20:14 am »
Thank you WriterOfMind, it reaches my heart. All the best.

Thank you DaltonG for your elaborate reply. You understand that I wasn't literally saying that it's impossible, but rather suggesting another (unusual?) kind of approach, pointing out that strange fact: if you're going to emulate worlds, you need to emulate minds, and vice-versa. So many things are yet to be discovered about the brain and the mind!

I made a new version, as required. It works with a wishlist organized by domains. The domain of a wish is something that can't take several directions simultaneously. For example, an NPC cannot both attack you and run away! So when conflicts appear, "arbiters" solve them before domain "changers" can build the next world state. Here is the code with a simple example.

Code: text

function World(opt = {}) {
   
    this.systems = opt.systems || [];
    this.arbiters = opt.arbiters || {};
    this.changers = opt.changers || {};
    this.things = opt.things || {};

    this.livingThings = new Set();
    this.cutRequests = [];
    this.delRequests = [];
    this.wishlist = {};
}



World.prototype.genId = (function() {
    let id = 0n;
    return function(prefix) {
        return prefix + (id++);
    }
})();



World.prototype.live = function() {
   
    // add to list of things that can change
    for (let arg of Array.from(arguments))
        for (let tid of Array.isArray(arg) ? arg : [arg])
            this.livingThings.add(tid);
}



World.prototype.partof = function(compoundId, componentId) {

    // getter: get things which are part of argument 1
    if (!componentId) return this.things[compoundId].madeof;

    // setter: attach a new component to argument 1
    this.things[compoundId].madeof.push(componentId);
    this.things[componentId].partof.push(compoundId);

    // they are now active
    this.live(compoundId, componentId);
}



World.prototype.madeof = function(componentId, compoundId) {

    // getter: get things which are made of argument 1
    if (!compoundId) return this.things[componentId].partof;

    // setter: attach argument 1 to a new compound
    this.things[compoundId].madeof.push(componentId);
    this.things[componentId].partof.push(compoundId);

    // they are now active
    this.live(compoundId, componentId);
}



World.prototype.thing = function(t = {}, edges) {
   
    // getter version
    if (typeof t == "string")
        return this.things[t.toString()];
   
    // setter version
    let id = this.genId('T');
    this.things[id] = {
        id,
        value: t,
        next: null,
        partof: [],
        madeof: []
    };

    // edges can be set up at creation
    // things they link must already exist
    if (edges) {
        if (edges.partof)
            for (let compoundId of edges.partof)
                this.madeof(id, compoundId);
        if (edges.madeof)
            for (let componentId of edges.madeof)
                this.partof(id, componentId);
    }
   
    // new things need to be handled
    this.live(id);
   
    return id;
}



World.prototype.cut = function(tid1, tid2) {
   
    // edge-cuts are not immediate
    // they are requested first
    this.cutRequests.push([tid1, tid2]);
}



World.prototype.cutNow = function(tid1, tid2) {

    // if edges still exist
    if (!((tid1 in this.things) && (tid2 in this.things))) return;

    // all of these are active now
    this.live(
        tid1,
        tid2,
        this.things[tid1].partof,
        this.things[tid1].madeof,
        this.things[tid2].partof,
        this.things[tid2].madeof
    );

    // tid1 is not part of tid2 anymore
    this.things[tid1].partof =
        this.things[tid1].partof.filter(tid => tid != tid2);

    // tid1 is not made of tid2 anymore
    this.things[tid1].madeof =
        this.things[tid1].madeof.filter(tid => tid != tid2);

    // tid2 is not part of tid1 anymore
    this.things[tid2].partof =
        this.things[tid2].partof.filter(tid => tid != tid1);

    // tid2 is not made of tid1 anymore
    this.things[tid2].madeof =
        this.things[tid2].madeof.filter(tid => tid != tid1);
}



World.prototype.del = function(tid) {
   
    // thing deletions are not immediate
    // they are requested first
    this.delRequests.push(tid);
}



World.prototype.delNow = function(tid) {

    // if things still exist
    if (!(tid in this.things)) return;

    // surroundings are active   
    this.live(
        this.things[tid].partof,
        this.things[tid].madeof
    );

    // they're not part of anything anymore
    for (let compoundId of this.things[tid].partof)
        this.things[compoundId].madeof =
            this.things[compoundId].madeof.filter(t => t != tid);
       
    // they're not made of anything anymore
    for (let componentId of this.things[tid].madeof)
        this.things[componentId].partof =
            this.things[componentId].partof.filter(t => t != tid);

    delete this.things[tid]
}



World.prototype.arbiter = function(domain, body) {
   
    this.arbiters[domain] = body;
}



World.prototype.changer = function(domain, body) {
   
    this.changers[domain] = body;
}



World.prototype.system = function(opt) {
   
    let id = this.genId('S');
   
    // systems will run in order of creation
    this.systems.push({
        id,
        // triggers is a list of qualifying functions
        triggers: opt.triggers,
        // template function calculates the next world state
        template: opt.template,
        // systems may be deactivated dynamically
        active: !opt.inhibited
    });
    return id;
}



World.prototype.status = function(sid, active) {
   
    if (arguments.length == 1)
        // toggle
        this.systems[sid].active = !this.systems[sid].active;
   
    else
        // set
        this.systems[sid].active = !!active;

    return this.systems[sid].active;
}



World.prototype.qualify = function(system, thing) {
   
    // each trigger of a system
    // must find at least 1 component
    // that meets its requirements
    for (let trigger of system.triggers) {
        let greenlight = false;
        for (let componentId of thing.madeof)
            if (trigger(this.things[componentId])) {
                greenlight = true;
                break;
            }
        // else the system does not qualify
        if (!greenlight) return false;
    }
    return true;
}



World.prototype.step = function() {
   
    // run systems
    // if they are active
    // and where they qualify
    // to prepare the next world state
    for (let system of this.systems)
        if (system.active)
            for (let tid of this.livingThings.values())
                if (this.qualify(system, this.things[tid])) {
                    let wish = system.template(this.things[tid]);
                    if (wish) {
                        if (!this.wishlist[wish.domain])
                            this.wishlist[wish.domain] = [];
                        this.wishlist[wish.domain].push(wish.decision);
                    }
                }

    // reset the list of active things
    this.livingThings.clear();

    // if there are conflicts on a domain
    // solve them if an arbiter is deployed on this domain
    for (let domain in this.wishlist)
        if (this.arbiters[domain])
            this.wishlist[domain] =
                this.arbiters[domain](this.wishlist[domain]);

    // make the next world state actual
    for (let domain in this.wishlist)
        this.changers[domain](this.wishlist[domain]);
    this.wishlist = {};

    // apply edge-cut requests
    for (let request of this.cutRequests)
        this.cutNow(request[0], request[1]);
    this.cutRequests = [];

    // apply thing deletion requests
    for (let request of this.delRequests)
        this.delNow(request);
    this.delRequests = [];
}



// ==============================



let w = new World();



w.arbiter("console logging", function(decisionList) {
   
    return decisionList.join(' & ');
});



w.changer("console logging", function(decision) {
   
    console.log(decision);
});



w.system({
    triggers: [
        function(component) {
           
            return component.value.type == "human";
        }
    ],
    template: function(thing) {
       
        return {
            domain: "console logging",
            decision: thing.value.who
        }
    }
});



let you = w.thing({ who: "you" }, {
    madeof: [
        w.thing({ type: "human" }),
        w.thing({ x: 6, y: 8 })
    ]
})



let me = w.thing({ who: "me" }, {
    madeof: [
        w.thing({ type: "human" }),
        w.thing({ x: 5, y: 8 })
    ]
})



w.step();


It should play nice with Lazutkin's Unification for JS...

Edit: added a "living nodes" tracker, to avoid looping over inactive things
« Last Edit: December 20, 2021, 01:47:37 pm by Zero »
We're not something that is changing. We are the change of something.

*

Zero

  • Trusty Member
  • **********
  • Millennium Man
  • *
  • 1198
  • Qu'aurai-je la satisfaction d'avoir accompli ?
Re: A world is a mind
« Reply #9 on: December 21, 2021, 03:53:10 pm »
Working on this really reveals things about how I work. I'm learning about myself.

When I approach Ai, or similar "high" subject (like deeply emulating a world), I stay too general, abstract, like disconnected from an actual working application. On the other hand, when I create less "noble" stuff (like games), my approach is direct and quick.

I need to find an equilibrium on this.


Here is an example of the wanted behavior.
- The guy has an "eyes" component, so he can see
- He has a curse that makes him blind, he can't see.
- But he also has a magical ring that protects him from curses, he can see.
- Unfortunately he is nearby an evil god statue which cancels the effects of any magical ring. He can't see.
« Last Edit: December 21, 2021, 08:22:50 pm by Zero »
We're not something that is changing. We are the change of something.

*

MagnusWootton

  • Starship Trooper
  • *******
  • 354
Re: A world is a mind
« Reply #10 on: December 22, 2021, 05:06:18 am »
On the other hand, when I create less "noble" stuff (like games), my approach is direct and quick.

A video game is a world,   so if the world was the mind,  then this is the only world the mind understands.

*

Zero

  • Trusty Member
  • **********
  • Millennium Man
  • *
  • 1198
  • Qu'aurai-je la satisfaction d'avoir accompli ?
Re: A world is a mind
« Reply #11 on: December 22, 2021, 10:03:34 am »
Yes, there's no reason why I should handle them differently.

As the example suggests, the architecture should be so it is always possible to add new content without refactoring existing code. That's the challenge.

Say the behavior of an actor depends on its components. When the actor receives a message, a lookup is done in its components, to collect behaviors. Instead of a wishlist, it is a wish stack. Behaviors have a weight. You start from the weakest and go through all of them, to the strongest. Each behavior receives the wish stack as input, and output an item that gets pushed on the stack. When all of them are done, the top of the stack is executed. So you can always add new behaviors, with a stronger weight, to add features.

I'll try that.

Example. A door has an "openable" component, so when it receives an "open" order, it opens. Then you implement a "lockable" component, with a stronger weight that "openable". When the door receives an "open" message, since "lockable" is stronger than "openable", it can prevent the door from opening. And so on.
We're not something that is changing. We are the change of something.

*

MagnusWootton

  • Starship Trooper
  • *******
  • 354
Re: A world is a mind
« Reply #12 on: December 22, 2021, 11:08:43 am »
Example. A door has an "openable" component, so when it receives an "open" order, it opens. Then you implement a "lockable" component, with a stronger weight that "openable". When the door receives an "open" message, since "lockable" is stronger than "openable", it can prevent the door from opening. And so on.

That's very similar to code that goes in the vintage adventure game genre.   symbolic logic.
I swear,  if you make an adventure game about doing dishes in the kitchen, and its detailed enough,  you can get a robot to do the dishes! =)

Its kinda like physics, except its only at the symbolic level instead,  with no vectors or numbers,  just words.

*

Zero

  • Trusty Member
  • **********
  • Millennium Man
  • *
  • 1198
  • Qu'aurai-je la satisfaction d'avoir accompli ?
Re: A world is a mind
« Reply #13 on: December 22, 2021, 11:35:57 am »
I think you're right, and that's why I post here in AiDreams. But there can be numbers and word vectors if we want. After all, there's a lot of numbers in game.

Though, while this architecture makes it easy to write an increasingly complex machine, it makes learning a harder process...

Edit: here is a first shot

Code: text

function World(opt = {}) {
   
    this.things = opt.things || {};
    this.behaviors = opt.behaviors || {};
    this.changers = opt.changers || {};
    this.views = opt.views || {};

    this.cutRequests = [];
    this.delRequests = [];
}



World.prototype.genId = (function() {
    let id = 0n;
    return function(prefix) {
        return prefix + (id++);
    }
})();



World.prototype.update = function(tid) {
   
    this.updateViews(tid);
    this.collectBehaviors(tid);
}



World.prototype.collectBehaviors = function(tid) {
   
    let list = [];

    // behaviors depend on the components
    for (let componentId of this.things[tid].madeof)
        if (this.things[componentId].value.behaviors)
            for (let behavior of this.things[componentId].value.behaviors)
                if (!list.includes(behavior))
                    list.push(behavior);
   
    let that = this;
    list.sort(
        function(a, b) {
            return that.behaviors[a].weight - that.behaviors[b].weight;
        }
    );
   
    this.things[tid].orderedBehaviors = list;
}



World.prototype.partof = function(compoundId, componentId, noUpdate) {

    // getter: get things which are part of argument 1
    if (!componentId) return this.things[compoundId].madeof;

    // setter: attach a new component to argument 1
    this.things[compoundId].madeof.push(componentId);
    this.things[componentId].partof.push(compoundId);
   
    if (!noUpdate) this.update(compoundId);
}



World.prototype.madeof = function(componentId, compoundId, noUpdate) {

    // getter: get things which are made of argument 1
    if (!compoundId) return this.things[componentId].partof;

    // setter: attach argument 1 to a new compound
    this.things[compoundId].madeof.push(componentId);
    this.things[componentId].partof.push(compoundId);
   
    if (!noUpdate) this.update(compoundId);
}



World.prototype.thing = function(t = {}, edges) {
   
    // getter version
    if (typeof t == "string")
        return this.things[t.toString()];
   
    // setter version
    let id = this.genId('T');
    this.things[id] = {
        id,
        value: t,
        partof: [],
        madeof: [],
        orderedBehaviors: []
    };

    // edges can be set up at creation
    // things they link must already exist
    if (edges) {
       
        if (edges.partof)
            for (let compoundId of edges.partof)
                this.madeof(id, compoundId);
       
        if (edges.madeof)
            for (let componentId of edges.madeof)
                this.partof(id, componentId, true);
       
        this.update(id);
    }
   
    return id;
}



World.prototype.cut = function(tid1, tid2) {
   
    // edge-cuts are not immediate
    // they are requested first
    this.cutRequests.push([tid1, tid2]);
}



World.prototype.cutNow = function(tid1, tid2) {

    // if edges still exist
    if (!((tid1 in this.things) && (tid2 in this.things))) return;

    // tid1 is not part of tid2 anymore
    this.things[tid1].partof =
        this.things[tid1].partof.filter(tid => tid != tid2);

    // tid1 is not made of tid2 anymore
    this.things[tid1].madeof =
        this.things[tid1].madeof.filter(tid => tid != tid2);

    // tid2 is not part of tid1 anymore
    this.things[tid2].partof =
        this.things[tid2].partof.filter(tid => tid != tid1);

    // tid2 is not made of tid1 anymore
    this.things[tid2].madeof =
        this.things[tid2].madeof.filter(tid => tid != tid1);

    this.update(tid1);
    this.update(tid2);
}



World.prototype.del = function(tid) {
   
    // thing deletions are not immediate
    // they are requested first
    this.delRequests.push(tid);
}



World.prototype.delNow = function(tid) {

    // if things still exist
    if (!(tid in this.things)) return;

    // they're not part of anything anymore
    for (let compoundId of this.things[tid].partof) {
       
        this.things[compoundId].madeof =
            this.things[compoundId].madeof.filter(t => t != tid);
   
        this.update(compoundId);
    }
   
    // they're not made of anything anymore
    for (let componentId of this.things[tid].madeof) {
       
        this.things[componentId].partof =
            this.things[componentId].partof.filter(t => t != tid);
    }
   
    delete this.things[tid];
}



World.prototype.everything = function() {
   
    return Object.keys(this.things);
}



World.prototype.behavior = function(name, weight, wishmaker) {

    // check no existing behavior has the same weight
    for (let b in this.behaviors)
        if (this.behaviors[b].weight == weight)
            throw `behavior "${name}" has the same weight (${weight}) as "${b}"`;
   
    // check no existing behavior has the same name
    if (name in this.behaviors)
        throw `behavior "${name}" already defined`;
   
    this.behaviors[name] = { name, weight, wishmaker };
}



World.prototype.changer = function(name, body) {
   
    this.changers[name] = body;
}



World.prototype.send = function(tid, message) {

    let wishStack = [];
   
    // all behaviors contribute to the wish stack
    for (let b of this.things[tid].orderedBehaviors) {
        let wish = this.behaviors[b].wishmaker(
            tid,
            message,
            wishStack
        );
        if (wish) wishStack.push(wish);
    }
   
    if (wishStack.length == 0) return;
   
    let finalWish = wishStack[wishStack.length - 1];
   
    // call for actual changes
    if (finalWish.changer)
        this.changers[finalWish.changer](
            tid,
            finalWish
        );
}



World.prototype.value = function(tid, key, val) {
   
    // all getter
    if (!key) return this.things[tid].value;
   
    // key getter
    if (!val) return this.things[tid].value[key];
   
    // setter
    this.things[tid].value[key] = val;
   
    // update
    for (let id of this.things[tid].partof)
        this.update(id);
}



World.prototype.assign = function(tid, val) {
   
    Object.assign(this.things[tid].value[key], val);
   
    // update
    for (let id of this.things[tid].partof)
        this.update(id);
}



World.prototype.view = function(view, selectors) {
   
    // getter version
    if (!selectors)
        return Array.from(this.views[view].list.values());
   
    // setter version
    this.views[view] = {
        list: new Set(),
        selectors
    };
}



World.prototype.updateViews = function(tid) {

    for (let view in this.views) {
        let accept = true;
        // every selector must be satisfied
        for (let selector of this.views[view].selectors) {
            let greenlight = false;
            for (let componentId of this.things[tid].madeof)
                // one component is enough to satisfy the selector
                if (selector(this.things[componentId])) {
                    greenlight = true;
                    break;
                }
            if (!greenlight) {
                accept = false;
                break;
            }
        }
        if (accept) this.views[view].list.add(tid);
        else this.views[view].list.delete(tid);
    }
}



/*

when receiving a message
the behavior of a thing
depends on its components

*/



let w = new World();
let t = w.thing.bind(w);



w.changer("vision", function(tid, wish) {
   
    console.log("[vision] " + wish.vision);
});



w.behavior("sight", 1, function(tid, msg, wishStack) {
   
    if (msg.image)
        return {
            changer: "vision",
            vision: "you see " + msg.image
        }
});



w.behavior("protection from curses", 3, function(tid, msg, wishStack) {

    let uncurse;
    for (let wish of wishStack)
        if (wish.type == "curse")
            uncurse = wish.blocked;

    return uncurse;
});



w.behavior("blind curse", 2, function(tid, msg, wishStack) {
   
    let lastWish = wishStack[wishStack.length - 1];
   
    if (lastWish.changer == "vision")
        return {
            type: "curse",
            blocked: lastWish
        };
});



w.view("able to see", [
    component => component.value.organ == "eyes"
]);



console.log(w.view("able to see"));



let me = t({ who: "me" }, {
    madeof: [
        t({ race: "gobelin" }),
        t({ organ: "eyes", behaviors: ["sight"] }),
        t({ object: "ring", behaviors: ["protection from curses"] }),
        t({ curse: "blind", behaviors: ["blind curse"] }),
    ]
});



console.log(w.view("able to see"));



w.send(me, { image: "gold coins" })


Edit: I added views à la NoSQL
« Last Edit: December 22, 2021, 05:11:38 pm by Zero »
We're not something that is changing. We are the change of something.

*

OllieGee

  • Nomad
  • ***
  • 62
    • The ultimate frequency blog
Re: A world is a mind
« Reply #14 on: January 13, 2022, 08:02:30 am »
I don't disagree, but I wonder for anyone interested or having the time to build a simulated mind (or world) which one might be faster to do...