简体   繁体   中英

Simpler / more efficient method of nested if … else flow?

I'm currently working on an emulation server for a flash-client based game, which has a "pets system", and I was wondering if there was a simpler way of going about checking the level of specified pets.

Current code:

public int Level
{
    get
    {
        if (Expirience > 100) // Level 2
        {
            if (Expirience > 200) // Level 3
            {
                if (Expirience > 400) // Level 4 - Unsure of Goal
                {
                    if (Expirience > 600) // Level 5 - Unsure of Goal
                    {
                        if (Expirience > 1000) // Level 6
                        {
                            if (Expirience > 1300) // Level 7
                            {
                                if (Expirience > 1800) // Level 8
                                {
                                    if (Expirience > 2400) // Level 9
                                    {
                                        if (Expirience > 3200) // Level 10
                                        {
                                            if (Expirience > 4300) // Level 11
                                            {
                                                if (Expirience > 7200) // Level 12 - Unsure of Goal
                                                {
                                                    if (Expirience > 8500) // Level 13 - Unsure of Goal
                                                    {
                                                        if (Expirience > 10100) // Level 14
                                                        {
                                                            if (Expirience > 13300) // Level 15
                                                            {
                                                                if (Expirience > 17500) // Level 16
                                                                {
                                                                    if (Expirience > 23000) // Level 17
                                                                    {
                                                                        return 17; // Bored
                                                                    }
                                                                    return 16;
                                                                }
                                                                return 15;
                                                            }
                                                            return 14;
                                                        }
                                                        return 13;
                                                    }
                                                    return 12;
                                                }
                                                return 11;
                                            }
                                            return 10;
                                        }
                                        return 9;
                                    }
                                    return 8;
                                }
                                return 7;
                            }
                            return 6;
                        }
                        return 5;
                    }
                    return 4;
                }
                return 3;
            }
            return 2;
        } 
        return 1;
    }
}

Yes, I'm aware I've misspelt Experience, I had made the mistake in a previous function and hadn't gotten around to updating everything.

Use a SortedList<int, int> and iterate over it until you find a value that is higher than the value you are searching for. You can do it using a simple iteration as in the answer you have already accepted. Or it can be done elegantly using LINQ (at a slight performance cost):

SortedList<int, int> levels = new SortedList<int, int>
    {
        {0, 1},
        {100, 2},
        {200, 3},
        {400, 4},
        {600, 5},
    };

public int Experience;
public int Level
{
    get
    {
        return levels.Last(kvp => Experience >= kvp.Key).Value;
    }
}

Note that storing the 'level' is actually not strictly necessary as you can derive it from the index of the item in the list. It may be advantageous to use a simple List<int> that is sorted instead to prevent errors where you accidentally miss out a level, as in the solution you have already accepted.

If you want better performance you could use List.BinarySearch but I think the extra complexity is not worth it unless you have performance profiled and found that this is the bottleneck.

List<int> levels = new List<int> { 0, 100, 200, 400, 600 /* etc... */ };

int index = levels.BinarySearch(Experience);
int level;
if (index < 0)
{
    level = ~index;
}
else
{
    level = index + 1;
}
return level;
int[] levelCutoffs = new int[] {0, 100, 200, 400, 600 /*...*/};

for (int level = 0; level < levelCuttoffs.size; ++level) {
    if (Experience < levelCuttofs[level])
        return level;
}
return levelCuttoffs.size;

Edit: altered to use Bradley Mountford's suggestion.

@Mark's suggestion is a reasonable one. You could also reverse the order of evaluating the experience to un-nest the ifs:

if (Expirience > 23000) return 17; 
if (Expirience > 17500) return 16;
//... and so on.

But I would probably just use an regular C# array and the BinarySearch method, which can return the index of the matching item or the 2's complement of the least item that is just larger than the value you've searched for:

int[] levelThresholds = new[] { 100, 200, 400, 600, 1000, ..., 23000 };

int experience = 11403;
int index = Array.BinarySearch( levelThresholds, experience );
// returns either the index, or the 2's complement of the 
// first index greater than the value being sought
int level = index < 0 ? ~index : index+1;

How about a simple formula, based on a logarithmic function?

Something like

return Math.Floor(LinearScale * Math.Log(Expirience, LogBase));

You're going from most inclusive to most exclusive. If you go the other direction, you don't need all the nesting.

if (Expirience > 23000) // Level 17
  {
    return 17; // Bored
  }
  else if (Expirience > 17500) // Level 16
  {
    return 16;
  }
  else if (Expirience > 13300) // Level 15
  {
    return 15;
  }
  ...

I would take Mark Byers answer a step further. Since is slightly confusing (I'd forget which int is which) Instead make a sorted list of

SortedList<UserLevel>

That way you can define much more than just a required number of experience points to each level. you could also assign a Name, ie "Uber Elite Super Level" and perhaps even a custom welcome message at each level.

If the experience algorithm can be reduced to a function, it should use functional calculation, ie:

return (Expirience/200); // if each level was 200 xp etc

However your nested if's above don't seem to apply to any function curve, there is the ? operator:

return
 (Expirience > 23000) ? 17 :
 (Expirience > 17500) ? 16 :
 (Expirience > 13300) ? 15 : 
 .. etc ..
 (Expirience > 100) ? 2 : 1;

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM