0

I am programming a simulation thingy that I can use as a basis for a game or something later. I am programming in C# and with Unity. Unity is up to date on version 2017.1.0f3 (or 3.3.0.2 ?).

The simulation just spawns some random people and when they get older they may search for a partner and reproduce themselves.

Now I have some weird behaviour in that "search for a partner"-method. I will show the code below in a second. The method takes a list of people as an argument and validates that list to filter out every person that is older than 15 years and don't have a partner already. Also related persons get filtered out because I don't really want incest inside my simulation .. (yet? ^^)

To clarify my problem: in the List<> called potentialPartners are somehow people already having a partner. I am sure that it is no multithreading-caused problem because those partners were not set in the same frame. Also I by myself don't do any multithreading stuff yet, there're just the threads Unity creates as default.

    public void SearchForPartner(List<PawnLogic> pawnsInRange)
    {
        if (!this.PartnerAllowed)
            return;

        System.Random rnd = new System.Random();

        List<PawnLogic> potentialPartners = new List<PawnLogic>();
        var pP = pawnsInRange.Where(x => x.PartnerAllowed && x.Gender != this.Gender && !this.IsKindred(x) && !x.IsKindred(this));
        if (pP.Count() > 0)
            potentialPartners.AddRange(pP);

        if (potentialPartners.Count == 0)
            return;

        this.Partner = potentialPartners[rnd.Next(0, potentialPartners.Count)];

        if (this.Partner.IsAlive)
        {
            this.Partner.Partner = this;

            if (this.News != null)
            {
                this.News.Invoke(this, new NewsEventArgs(this, this.FirstLastName + " and " + this.Partner.FirstLastName + " become a couple."));
            }

            if (Gender == 'M')
                this.Partner.SetNewLastname(this.thisPawn.LastnameNumber);
            else
                this.SetNewLastname(Partner.thisPawn.LastnameNumber);
        }
        else
            this.Partner = null;
    }

I guess my problem comes from the property "PartnerAllowed" because if I remember correctly the &&-operator only validates the right hand side if the left hand side returns true.

    public bool PartnerAllowed
    {
        get
        {
            return this.partner == null && this.Age >= 16;
        }
    }

Just to be complete here is the IsKindred-method.. I don't really think that my problem comes outside of this but maybe I am not seeing something important.

    public bool IsKindred(PawnLogic check)
    {
        if (Generation <= check.Generation - 4)
            return false;
        if ((Father == null || Mother == null || check.Father == null || check.Mother == null) && Siblings.Count == 0)
            return false;
        if (check == Mother || check == Father)
            return true;
        if (Siblings.Contains(check))
            return true;
        for (int i = 0; i < Siblings.Count; i++)
        {
            if (Siblings[i].Children.Contains(check))
                return true;
        }
        if (Father != null && Father.IsKindred(check))
            return true;
        if (Mother != null && Mother.IsKindred(check))
            return true;

        return false;
    }

My Partner-property looks like this:

    public PawnLogic Partner
    {
        get
        {
            if (this.partner == null && this.thisPawn.PartnerNumber != null)
            {
                int indexOfPartner = this.thisPawn.PartnerNumber.ToInt();
                if (indexOfPartner != -1)
                    this.partner = new PawnLogic(indexOfPartner);
                else
                    this.partner = null;
            }

            return this.partner;
        }
        private set
        {
            if (value == null)
                this.thisPawn.PartnerNumber = null;
            else
            {
                this.thisPawn.PartnerNumber = value.Number;
                this.partner = value;
            }
        }
    }

I have no idea how to fix this. Especially because it works in another program which I wrote first. But I needed to transfer the code to this new project because Unity doesn't use .Net 4.6 yet. Maybe there was a change in Linq's behaviour between the framework-versions? Do someone can help me?

It is just a private project, but I want it to work properly anyway. :P

Let me know if you need more code or explanation to understand what is happening, what is supposed to happen or how something works.

Thank you for your time and effort :)

Aoki.Miku
  • 37
  • 1
  • 10
  • Try `var pP = pawnsInRange.Where(x => x.PartnerAllowed);` and see if it's returning only those without partner and more than 15 years. – Anis Alibegić Sep 06 '17 at 00:28
  • Are `this.partner` and `this.Partner` exactly the same thing (i.e. is one a member variable, and the other a simple property that exposes it), or are they different in any way? – hatchet - done with SOverflow Sep 06 '17 at 00:38
  • @Spectarion Nope, still people with partners. Only the age-constraint works. – Aoki.Miku Sep 06 '17 at 00:40
  • @hatchet yes they are. The lower case `this.partner` is a private field that gets set in the setter of the property `this.Partner` – Aoki.Miku Sep 06 '17 at 00:43
  • So the `Partner` getter simply regurgitates `this.partner`? – hatchet - done with SOverflow Sep 06 '17 at 00:44
  • @hatchet It is not that easy. I have a pure dataclass that does nothing but holds the atomic data for each of my so called pawns. So I have to do some validation inside of the getter and setter of `this.Partner`. I will edit my question to show the code too. – Aoki.Miku Sep 06 '17 at 00:49
  • Just out of curiosity, why do you perform both these checks: `!this.IsKindred(x) && !x.IsKindred(this));`? Is there any possibility that one would return `true` and the other wouldn't? And if so, isn't that a bug? – Rufus L Sep 06 '17 at 01:04
  • You state, *"it works in another program which I wrote first. But I needed to transfer the code to this new project"*. So, you might start by looking at what's different in your new project. If the code you've posted works correctly elsewhere, then that's likely not the problem. – Rufus L Sep 06 '17 at 01:16
  • @RufusL tbh I forgot the intention of that double check. But if I remember correctly there was a situation when inside the method checking the siblings and/or the children it returned false which caused one of my pawns to marry his niece .. or it was the other way around that she married her uncle.. something like that.. the double check was the easiest approach for that but you are right, I should include it in the method – Aoki.Miku Sep 06 '17 at 01:19
  • @RufusL the only thing that works/looks different is the `Partner` property.. but in the end it returns in both programs the `partner` field if it is not null. The program that works correctly just uses .Net 4.6 but this program I show here uses another version because Unity is build on and using an older .Net version (I'm not sure which one atm). I think it is version 3.5 or something? – Aoki.Miku Sep 06 '17 at 01:27
  • 2
    One potential bug you can remove is to get rid of all references to the private backing field (lower case `partner`) in your code, except from the `get` and `set` accessors of the `Partner` property. All other code should use the `Partner` property, not the `partner` field. This is because if some of your code is only checking if the field `partner == null` and other code uses the `Partner` property, you may get mixed results since the `getter` will `set` the `partner` field if `PartnerNumber` is not `-1`. – Rufus L Sep 06 '17 at 01:41
  • *"But I needed to transfer the code to this new project because Unity doesn't use .Net 4.6 yet"* Not really. It is now supported in Unity 2017 and above. See [this](https://stackoverflow.com/questions/45097965) post for more info. – Programmer Sep 06 '17 at 05:59
  • 1
    @Programmer ohh, thank you for that advice. I didn't know I can switch to .Net 4.6 .. That will make some things less complicated as I work normally with 4.6 – Aoki.Miku Sep 06 '17 at 11:11
  • @RufusL My `PartnerAllowed` property was the only line that used the lower case `partner` .. I don't understand why, but your suggestion did work. I was in debugmode and looked up the values in the `potentialPartners` list but even the lowercase `partner` was not null .. that got me confused because it is not null but the `PartnerAllowed` check that for null and returns true ..? Now I check the uppercase `Partner` instead and it does work. Makes no sense to me but thank you anyway. – Aoki.Miku Sep 06 '17 at 11:20

0 Answers0