Post reply

Warning - while you were reading 89 new replies have been posted. You may wish to review your post.

Note: this post will not display until it's been approved by a moderator.

Name:
Email:
Subject:
Message icon:

shortcuts: hit alt+s to submit/post or alt+p to preview

Please read the rules before you post!


Topic Summary

Posted by: Caesar
« on: Today at 06:59:23 AM »

Hi! It's been a while since I played, but I'm getting back into the game again. I wanted to read up on the mechanics, when I noticed the wiki doesn't work. I think I read that it may be a temporary issue but I couldn't find a good post on it. Does anyone have a clearer idea what's going on with the wiki?

Thanks in advance!

Did anyone have any information on the wiki?

It is still a temporary problem, just longer-lasting than initially anticipated.

You can read up on a lot of the mechanics in the c# changes thread.
You can also find FAQs and ask questions in the Aurora discord.

Cheers! Both for the info about the wiki and the good referrals. :)
Posted by: skoormit
« on: Today at 06:45:25 AM »

Hi! It's been a while since I played, but I'm getting back into the game again. I wanted to read up on the mechanics, when I noticed the wiki doesn't work. I think I read that it may be a temporary issue but I couldn't find a good post on it. Does anyone have a clearer idea what's going on with the wiki?

Thanks in advance!

Did anyone have any information on the wiki?

It is still a temporary problem, just longer-lasting than initially anticipated.

You can read up on a lot of the mechanics in the c# changes thread.
You can also find FAQs and ask questions in the Aurora discord.
Posted by: Caesar
« on: Today at 03:58:29 AM »

Hi! It's been a while since I played, but I'm getting back into the game again. I wanted to read up on the mechanics, when I noticed the wiki doesn't work. I think I read that it may be a temporary issue but I couldn't find a good post on it. Does anyone have a clearer idea what's going on with the wiki?

Thanks in advance!

Did anyone have any information on the wiki?
Posted by: db48x
« on: Yesterday at 06:56:47 PM »

So now you have made me curious, I started reading about it. Some people expressed a view that IEnumerable  only guarantees an enumeration and doesn't guarantee the order of execution (even if ordered beforehand). However, as I read it, its the same execution as list because the latter inherited the former. Which is correct?

Err, both, if I understand the question. An IEnumerable method returns an IEnumerator which has a MoveNext method that returns the next item. Calling that method is what triggers the enumerator to start doing its job. If you use a foreach loop, C# calls MoveNext for you until the enumerator is exhausted.

Each Enumerable method, such as Select or Except or OrderBy, returns a different IEnumerator implementation that stores any state that it needs plus the next IEnumerator along in the chain. For example, Select takes a projection function that maps from one type to another, and uses it to transform all of the elements of the enumeration into the result type. You could implement its IEnumerator approximately like this:

Code: [Select]
public class SelectEnumerator : IEnumerator
{
    private IEnumerator _inner;
    private Func<TSource, i32, TResult> _func;
    private TResult _current;

    public bool MoveNext()
    {
        _current = null;
        return _inner.MoveNext();
    }

    object IEnumerator.Current
    {
        get
        {
            if (_current) return _current;
            return _current = _func(_inner.Current);
        }
    }
}

The Where method is similar, but it only returns elements where the predicate returns true. You could write it approximately like this:

Code: [Select]
public class WhereEnumerator : IEnumerator
{
    private IEnumerator _inner;
    private Func<TSource, Boolean> _func;

    public bool MoveNext()
    {
        foreach (var e in _inner) {
            if (_func(e)) {
                return true;
            }
        }
        return false;
    }

    object IEnumerator.Current
    {
        get
        {
            return _inner.Current;
        }
    }
}

So to answer your question, the various Enumerable methods that you call only create these IEnumerator objects, and each Enumerator only runs enough code to get you the next item along. The execution of all of the Enumerators is interleaved, since each one calls the next one in the chain at least once. With some data sources the order of the results might vary, since data might come in from a database in an arbitrary order (for example), but since you are starting with a List then that will never happen. The elements returned by the enumerator will always be in the same order as they were in the original list, at least until you sort them.


EDIT

I just ran an experiment for the missile salvo list on the fleet window, which I just updated.

[…]

I ran both functions several times and in every case, the List version is faster than the IEnumerable version. It may be that the IEnumerable is faster to create, but the List seems to be faster to use. Maybe because everything is preloaded into memory for the List, whereas the IEnumerable has to retrieve the information as needed.

Of course I would need to see all of the code, and to know how you measured the performance to be able to say why that might be. See below…

Further reading suggests that every time you access a method or property of the same element within an IEnumerable foreach, it has to retrieve it again. A list already has it in memory.

Note quite. Notice that IEnumerator has a property called Current that holds the current value. They are all written so that they don't do any extra work if you retrieve that value more than once; you can see how I did that in SelectEnumerator above. And anyway, since you use a foreach loop C# is assigning that value to a local variable anyway. It doesn’t have to go back to the enumerator at all even if you access multiple properties or methods on the value that local variable holds.

So its likely that IEnumerable  is faster if you are doing very little with the data you enumerate, but List is faster if you want to access each element more than once (either in multiple iterations, or getting using multiple properties/methods for each element of a single iteration).

This is definitely true. If you need to multiple values from the enumeration at once, for example the nth − 1 element as well as the nth, then you need to write it in such a way that the enumerator doesn't have to be reset back to the start and work it’s way back down to the previous element. It should be fairly hard to make that mistake just by using foreach loops though.
Posted by: Steve Walmsley
« on: Yesterday at 05:26:18 AM »

I don't want to turn this thread into a programming debate, which is one of the reasons that I rarely post code ;)

I hope that none of the other readers of this thread have been put out by our monopolization of the topic of discussion :)

Are you suggesting that instead of a new list, I use the LINQ without assigning to a new list as the target in the foreach loop?

If so, I prefer to avoid that. It's harder to read and harder to debug and those are more important to me than straight performance.

Yes, both the CurrentSystems and PossibleSystems variables would be IEnumerable<KnownSystem> instead of List<KnownSystem>. I can’t really see how the code would be more difficult to read, since everything else would be identical except that you would just not call ToList().

However, I suppose I know what you mean about debugging. You want to stop at a breakpoint and be able to view the lists in the debugger. I tend to forget that not everybody can use omniscient debugging yet (I use a debugger called Pernosco a lot, but it is for Linux only.) If I were using a regular debugger and I wanted to verify which systems had been in the final enumeration, I would add a conditional breakpoint inside the loop to print out some information about ks (the system name and number, for instance) and then continue execution. (In Pernosco you can do the same thing but you get all the information that would have been printed without having to actually run the program again.)

As for performance, if this code is just called once any time a fleet transits an unexplored jump point then it is probably irrelevant. Even though you make two whole copies of the list of systems (and you did just make that list significantly larger), that probably takes so little time that nobody will notice. But you might take a look to see if you have made this mistake in more important parts of the code. What is a very minor mistake here would be much more regrettable in the code that implements ship detection, for instance.

OK, I think I finally understand what you are driving at :)

I was concerned I would have the LINQ in the middle of the foreach statement, if I didn't assign it to a List() first and use that as the target for the foreach. Are you saying I could just replace the List<KnownSystem> = with  IEnumerable<KnownSystem> = , remove the ToList() and then use the IEnumerable as the target of the foreach. That would be the same in terms of readability and I assume I could check the contents of the IEnumerable instead of the List?

I basically picked up C# by writing it and figuring things out when I needed to, without any formal learning, so there will be gaps in my knowledge :)

So now you have made me curious, I started reading about it. Some people expressed a view that IEnumerable  only guarantees an enumeration and doesn't guarantee the order of execution (even if ordered beforehand). However, as I read it, its the same execution as list because the latter inherited the former. Which is correct?

EDIT

I just ran an experiment for the missile salvo list on the fleet window, which I just updated.

This is the ToList() version.

List<MissileSalvo> Salvos = Aurora.MissileSalvos.Values.Where(x => x.SalvoRace == this).OrderBy(x => x.SalvoSystem.SystemID).ThenBy(x => x.MissileSalvoID).ToList();

This is looped and various information is used to display missile salvos, using foreach (MissileSalvo ms in Salvos)

I then created a IEnumerable version of the same function

IEnumerable<MissileSalvo> Salvos = Aurora.MissileSalvos.Values.Where(x => x.SalvoRace == this).OrderBy(x => x.SalvoSystem.SystemID).ThenBy(x => x.MissileSalvoID);

I ran both functions several times and in every case, the List version is faster than the IEnumerable version. It may be that the IEnumerable is faster to create, but the List seems to be faster to use. Maybe because everything is preloaded into memory for the List, whereas the IEnumerable has to retrieve the information as needed.

EDIT2:

Further reading suggests that every time you access a method or property of the same element within an IEnumerable foreach, it has to retrieve it again. A list already has it in memory. So its likely that IEnumerable  is faster if you are doing very little with the data you enumerate, but List is faster if you want to access each element more than once (either in multiple iterations, or getting using multiple properties/methods for each element of a single iteration).
Posted by: db48x
« on: Yesterday at 02:01:39 AM »

I don't want to turn this thread into a programming debate, which is one of the reasons that I rarely post code ;)

I hope that none of the other readers of this thread have been put out by our monopolization of the topic of discussion :)

Are you suggesting that instead of a new list, I use the LINQ without assigning to a new list as the target in the foreach loop?

If so, I prefer to avoid that. It's harder to read and harder to debug and those are more important to me than straight performance.

Yes, both the CurrentSystems and PossibleSystems variables would be IEnumerable<KnownSystem> instead of List<KnownSystem>. I can’t really see how the code would be more difficult to read, since everything else would be identical except that you would just not call ToList().

However, I suppose I know what you mean about debugging. You want to stop at a breakpoint and be able to view the lists in the debugger. I tend to forget that not everybody can use omniscient debugging yet (I use a debugger called Pernosco a lot, but it is for Linux only.) If I were using a regular debugger and I wanted to verify which systems had been in the final enumeration, I would add a conditional breakpoint inside the loop to print out some information about ks (the system name and number, for instance) and then continue execution. (In Pernosco you can do the same thing but you get all the information that would have been printed without having to actually run the program again.)

As for performance, if this code is just called once any time a fleet transits an unexplored jump point then it is probably irrelevant. Even though you make two whole copies of the list of systems (and you did just make that list significantly larger), that probably takes so little time that nobody will notice. But you might take a look to see if you have made this mistake in more important parts of the code. What is a very minor mistake here would be much more regrettable in the code that implements ship detection, for instance.
Posted by: vorpal+5
« on: Yesterday at 01:40:57 AM »

Transponders: are they always ON for civilian ships? Why would I want to keep them on, as it broadcasts their position to potential hostiles? And what would happen if I turned them off?
Posted by: Steve Walmsley
« on: May 26, 2024, 06:23:19 PM »

Huh. It may be that C# works differently than I expected, but the docs don’t indicate that the OrderBy method modifies the underlying list.

It's not the OrderBy, it is the Except that precedes it.

The documentation for Except doesn’t say that it modifies the list either. It is my understanding that none of the Enumerable methods modify the underlying data.

I don't want to turn this thread into a programming debate, which is one of the reasons that I rarely post code ;)

Are you suggesting that instead of a new list, I use the LINQ without assigning to a new list as the target in the foreach loop?

If so, I prefer to avoid that. It's harder to read and harder to debug and those are more important to me than straight performance.

If not, maybe DM me with an example of the code as you would write it.
Posted by: Caesar
« on: May 26, 2024, 03:59:02 PM »

Hi! It's been a while since I played, but I'm getting back into the game again. I wanted to read up on the mechanics, when I noticed the wiki doesn't work. I think I read that it may be a temporary issue but I couldn't find a good post on it. Does anyone have a clearer idea what's going on with the wiki?

Thanks in advance!
Posted by: db48x
« on: May 26, 2024, 12:32:37 PM »

Huh. It may be that C# works differently than I expected, but the docs don’t indicate that the OrderBy method modifies the underlying list.

It's not the OrderBy, it is the Except that precedes it.

The documentation for Except doesn’t say that it modifies the list either. It is my understanding that none of the Enumerable methods modify the underlying data.
Posted by: Steve Walmsley
« on: May 26, 2024, 09:33:38 AM »

How can I calculate Aphelion and Perihelion from the values in FCT_SystemBody?

                    sb.Perihelion = sb.OrbitalDistance * (1 - sb.Eccentricity);
                    sb.Aphelion = sb.OrbitalDistance * (1 + sb.Eccentricity);
                    sb.SemiMinorAxis = sb.OrbitalDistance * Math.Sqrt(1 - (sb.Eccentricity * sb.Eccentricity));
Posted by: skoormit
« on: May 26, 2024, 09:12:22 AM »

How can I calculate Aphelion and Perihelion from the values in FCT_SystemBody?
Posted by: Steve Walmsley
« on: May 26, 2024, 09:04:59 AM »

Huh. It may be that C# works differently than I expected, but the docs don’t indicate that the OrderBy method modifies the underlying list.

It's not the OrderBy, it is the Except that precedes it.
Posted by: db48x
« on: May 25, 2024, 04:47:58 PM »

I think I copied the code after fixing it.

Ah, that explains it. Fair enough.

I need a temporary list because I don't want to modify the KnownSystems list.

Huh. It may be that C# works differently than I expected, but the docs don’t indicate that the OrderBy method modifies the underlying list.
Posted by: Droll
« on: May 25, 2024, 03:16:20 PM »

I think I copied the code after fixing it.

Code duplication detected, billions must die.  ;D