Welcome to Keen Software House Forums! Log in or Sign up to interact with the KSH community.
  1. You are currently browsing our forum as a guest. Create your own forum account to access all forum functionality.

double Min, Max, array - Skip

Discussion in 'Programming Questions and Suggestions' started by ElBordelo, Jan 22, 2017.

Thread Status:
This last post in this thread was made more than 31 days old.
  1. ElBordelo Trainee Engineer

    Messages:
    19
    I have some silly questions.

    First, I wanted to get Min and Max values in double arrays. Example:
    double[] CPX = new double[8];
    for (int i = 0; i < CubePositions.Length; i++)
    { int F = 0;
    CPX[F] += CubePositions.GetDim(0);
    F = F + 1;}

    double minCPX = CPX.Min();
    double maxCPX = CPX.Max(); //In VS it is ok, but in SE doesn´t work.

    Second, I need to delete the first value in another array. In guides I found, it can be done via Skip(), but it doesn´t work for me.

    DroneNumbers = DroneNumbers.Skip(1); //????
     
  2. Inflex Developer Staff

    Messages:
    397
    No big deal. Just misconfigured Visual Studio. Don't worry, fix is easy. Don't use these methods ;)

    `Min()`, `Max()` and `Skip()` are all so called "LINQ extension methods". Although they are all white-listed and in-game compiler accepts them, they need special `using` statement in C# file header. Your VS template probably has this one listed among others and thus VS accepts your code as valid while in-game compiler does not implicitly add it.

    To make sure you have correct script header make sure it's same as in template from following guide:
    http://forum.keenswh.com/threads/setup-visual-studio-for-se-programming.7385455/#post-1286989996

    There is "cheeky" way to get extensions to in-game scripts but since LINQ extensions is sort of special kind of methods I would suggest to any C# beginner to avoid them till you fully understand how it works and what problems may be introduced by incorrect usage.

    And lastly to your code snippet (`DroneNumbers = DroneNumbers.Skip(1);`). With assumption that your collection is list, you can simply call `DroneNumbers.RemoveAt(0)`
    https://referencesource.microsoft.com/#mscorlib/system/collections/generic/list.cs,877
     
  3. ElBordelo Trainee Engineer

    Messages:
    19
    Ok, so this is my workaround (found on the internet):

    Code:
      double minCPX = GetMinDim(CPX);
                double maxCPX = GetMaxDim(CPX);
            private double GetMaxDim(double[] array)
            {
                double Max = array[0];
                for(int i = 0; i < array.Length; i++)
                {
                    if(array[i] > Max)
                    {
                        Max = array[i];
                    }
                }
                return Max;
            }
    
            private double GetMinDim(double[] array)
            {
                double Min = array[0];
                for (int i = 0; i < array.Length; i++)
                {
                    if (array[i] < Min)
                    {
                        Min = array[i];
                    }
                }
                return Min;
            }
    Well, DroneNumbers isn´t List, but array (int[] DroneNumbers). Is there some method like RemoveAt() for arrays? Or should I rewrite it as array? Maybe, it would be easier in the end. :)

    Last question: Next code is part of my future DronePrinter.
    Idea is to have Drone named DronX (X=int) that would correspond to Connector named DroneDockX.
    So, I created int arrays of Connectors (DroneDocky) and Drons (DroneShipy) and I wanted to compare them, if any of Drones would be missing, I could automaticky create new DroneX.
    I apperantly miss the right logic for it. Do you know any elegant way to do it?

    Thanks to everyone for their contributions. :)

    Code:
    public Array DroneOrder() //Creates two int arrays and compares them, if some is missing =>drones to print
            {   //Gets individual numbers of DroneDocks
                int[] DroneDocky = new int[DroneDocks.Count];
                for (int i = 0; i < DroneDocks.Count; i++)
                {
                    DroneDocky[i] = int.Parse(DroneDocks[i].CustomName.Remove(0, 9));
                }
                //Gets individual numbers of Drones
                int[] DroneShipy = new int[DroneShips.Count];
                for (int i = 0; i < DroneShips.Count; i++)
                {
                    DroneShipy[i] = int.Parse(DroneShips[i].CustomName.Remove(8, 20).Remove(0, 5));
    
                    if (!DroneDocky.Contains(DroneShipy[i])) 	//Here is the problem!
                    {
                        for (int y = 0; y < DroneDocks.Count; y++)
                            DroneNumbers[y] = DroneDocky[i];
                    }
                } 
     
  4. albmar Trainee Engineer

    Messages:
    69
    No there isn't. Arrays have a fixed size. To get an array of a different size you need to create a new array and copy the values you want to keep into the new one, but I wouldn't do this, because it's too expensive for just "deleting" one element. If you would use a reference type (class etc.) one could assign a null value. But you use value type (int). The best choice of "deleting" would be moving it to the end and manage a variable that states the current size of your array.

    I think you mean a List here. And in my opinion you should rewrite your stuff to use a List. Internally it uses an array and manages the resizing for you. You also don't have to change much, since you can access the List like an array.:)
     
  5. Phoera Senior Engineer

    Messages:
    1,713
    for removing first element LinkedList can be better.
    also about min and max, do it in same loop, minmax at once.
     
  6. Inflex Developer Staff

    Messages:
    397
    [​IMG]

    Please don't use linked lists on modern CPUs. Especially not for small collections (< 1000 elements)!
    There are only few special cases when using liked list based data storing makes sense and PB scripting is surely not one of those.
     
  7. Phoera Senior Engineer

    Messages:
    1,713
    any proof?

    overhead for linked list is much lesser then for copying array.

    my advice will be reverse array and use list(first element is last, so we will remove from last)
     
  8. albmar Trainee Engineer

    Messages:
    69
    In theory, linked lists might be better in inserting and deleting elements. But due to spatial locality that modern architectures make use of it's better to use array structures like the generic List than linked lists. Also usually structures that uses arrays are implemented in a way that they won't "change the size" of its array each time an element is added or removed. Allocating a new array and copying the data to it will only occur if it's needed to, i.e. the capacity of the array is reached or there are only capacity/2 elements. So I have to agree with Inflex.

    You may also have a look at:

    The part with the graph is the best one. :D

    Beside that I don't think that it's really relevant to ElBordelo to use the most performant structure. What matters more here is the easy usage of managing elements, which both kinds of structures can do.
     
    • Agree Agree x 1
  9. ElBordelo Trainee Engineer

    Messages:
    19
    Thanks for your answers guys.
    I succesfully removed these problems, but more of them occured. :(
    In the spoiler, there is the entire code. I tried to translate everything important into english.
    Problem is, that PB returns: Script too complex, redesign and recompile the script.
    I have no idea, where the problem is.

    I was writting the script in the way, it should build drones automaticaly in correctly named factories and the number of the factories shouldn´t matter. (Piston extends to welders and slowly retacts, when Dron is created, it is corectly renamed....so I could create more drones of one type without interference).
    I know, it is long, but if someone have time, please tell me about most probable mistake.
    I am beginner in C#, so it shouldn´t be a problem to read it for you.
    P.S. Script compiles normally, it stops in CreateDroneSequence1();
    Thanks a lot

     
    Last edited: Jan 28, 2017
  10. Inflex Developer Staff

    Messages:
    397
    Every script you put and run inside PB is measured during run-time. Whenever your script exceed certain threshold of complexity during it's single run/invoke the "Script too complex" exception is thrown and your script is automatically terminated.
    It's a simple mechanism to protect game from freezes caused by PBs and some cheeky server killer scripts.

    The main observable restriction is so called "Instruction Counter". For each PB run you get pool of 50K instructions and once you reach this threshold, :clang:, script gets terminated.
    You can watch your current instruction count growing live during PB run so you can debug your script and see where you loose most instructions.

    To read current instruction count use following code:
    Code:
    void Main()
    {
    	this.Echo($"Current instruction count: {this.Runtime.CurrentInstructionCount}");
    
    	for(int i = 0; i < 10; i++); //Waste 10 instructions
    
    	this.Echo($"Current instruction count: {this.Runtime.CurrentInstructionCount}");
    }
    
    API reference:
    https://github.com/KeenSoftwareHous...odAPI/Ingame/IMyGridProgramRuntimeInfo.cs#L34
     
  11. Phoera Senior Engineer

    Messages:
    1,713
    if element count not fixed this is best solution.

    i replied to what TS tryed to do, is removing first and adding new to end, for lists this will always copy all elements except first.
    Linked list will avoid this.
    also about video, Stroustrup talks mainly about C/C++, .NET usually compress heap, so cache miss is small as possible and perfomance not affected.

    if element count is fixed, best solition is Circular Buffer.

    actually, i looked more precisely, we have int as type, which is value type, in that case List will be better. sorry.
    for classes this is another story ;)
     
  12. d4rky1989 Apprentice Engineer

    Messages:
    332
    Also it is important to not misunderstand the video: if you are using an ArrayList (i.e. the generic List<> in C#) you still do not avoid that the elements that are "stored" in the array are still located at the heap itself. By using ArrayLists only the pointers (unless it is a value type like int etc.) to the objects are located in that array.
    If I understand him correct he is talking about using the vector on struct-like data that gets allocated inside that array and not only a pointer to the array. So each entry of the vector has a memoy allocation of (sizeof(<struct-name>)) (i.e. stores the whole struct) and not (sizeof(*<struct-name>)) (i.e. stores the pointer to a struct)

    Edit:
    Yes, as it is a value type (int) the value gets stored inside of the array directly and this should be extremely fast vs linked lists
     
    Last edited: Jan 29, 2017
  13. Phoera Senior Engineer

    Messages:
    1,713
    this is what i sayd in last two lines of post.
     
  14. d4rky1989 Apprentice Engineer

    Messages:
    332
    Yes, didn't read the last line :p (just woked up then and was browsing a bit :D). But anyway. Not everybody knows why it is different with classes. So my post should it clearify further even it is still somehow rubbish explained. So the keywords one should look up and if one is interested are value and reference types.
     
  15. ElBordelo Trainee Engineer

    Messages:
    19
    Ok, script works....at least for one Factory, when I merge another one, it writes me about a mistake, which I cant find right now. Thx for help. :)
     
Thread Status:
This last post in this thread was made more than 31 days old.