2010-06-01 8 views
6

Je travaille actuellement sur un serveur d'émulation pour un jeu basé sur un client flash, qui a un "système d'animaux de compagnie", et je me demandais s'il y avait une façon plus simple de vérifier le niveau des animaux spécifiés.Méthode plus simple/plus efficace de flux imbriqué si ... sinon?

Code actuel:

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; 
    } 
} 

Oui, je sais que j'accusons mal orthographié, je l'avais fait l'erreur dans une fonction précédente et n'avait pas eu l'occasion de tout mettre à jour.

+15

Il n'y a aucun moyen ce n'est pas une question de plaisanterie. –

+1

Si vous n'êtes pas au courant (ne dites pas que vous n'êtes pas ... juste en train d'essayer d'être utile), "mettre à jour tout" n'est pas un processus onéreux. Cliquez avec le bouton droit sur "Expirience"> Refactor> Renommer. Bon à faire ... la plupart du temps (les vues ne seront pas mises à jour). –

+2

@George - ou quelqu'un lit TDWTF pour les exemples de code ... – GalacticCowboy

Répondre

13
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: modifié pour utiliser la suggestion de Bradley Mountford.

+0

C'est probablement le moyen le plus modulable. – Puppy

+4

Au lieu de renvoyer 17 pour la solution de secours, vous voudrez probablement renvoyer levelCuttoffs.size de sorte qu'il se redimensionne dynamiquement. –

+0

Ouais, cela ressemble à la meilleure solution à mon problème pour l'instant, car j'ai seulement besoin de renvoyer des entiers, pas des chaînes. Merci TreDubZedd. – Scott

22

Utilisez un SortedList<int, int> et parcourez-le jusqu'à ce que vous trouviez une valeur supérieure à la valeur recherchée. Vous pouvez le faire en utilisant une itération simple comme dans la réponse que vous avez déjà acceptée. Ou il peut être fait avec élégance LINQ (à un coût faible performance):

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; 
    } 
} 

Notez que le stockage du « niveau » est en fait pas strictement nécessaire comme vous pouvez le déduire de l'index de l'élément dans la liste. Il peut être avantageux d'utiliser un simple List<int> qui est trié à la place pour éviter les erreurs lorsque vous ratez accidentellement un niveau, comme dans la solution que vous avez déjà acceptée. Si vous voulez de meilleures performances, vous pouvez utiliser List.BinarySearch mais je pense que la complexité supplémentaire ne vaut pas la peine, sauf si vous avez des performances profilées et constaté que c'est le goulot d'étranglement.

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; 
+0

en effet, ma solution aussi bien. +1 – user29964

+0

Certainement. C'est ce qu'on appelle une approche axée sur les tables. Ce que vous avez là-bas, c'est un tas de données que vous avez écrites en tant que déclarations de contrôle. Ecrivez-le en tant que données à la place. –

+0

Peut-être corriger l'orthographe de leur variable? Cela me semble tellement mou. – ChaosPandion

2

Vous allez de la plus inclusive à la plus exclusive. Si vous allez dans l'autre direction, vous n'avez pas besoin de toute l'imbrication.

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

Vous pouvez également utiliser cette même approche avec une instruction Switch au lieu de toutes les instructions if ... else. – AllenG

+2

@AllenG: l'instruction 'switch' de C# ne supporte pas les plages IIRC. – kennytm

+1

Vous n'avez même pas besoin du 'else' – Patrick

4

@ La suggestion de Mark est raisonnable. Vous pouvez aussi inverser l'ordre d'évaluer l'expérience à un nid l'ifs:

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

Mais je probablement utiliser un réseau régulier C# et la méthode BinarySearch, qui peut renvoyer l'index de l'élément correspondant ou 2 complément à du moins élément qui est juste supérieure à la valeur que vous avez recherché pour:

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; 
+1

+1 BinarySearch est O (log n) et compte tenu des marques de niveau sont corrigé, cela fonctionnera mieux que juste itérer une liste de ifs ou une liste de marques de niveau. – David

+0

-1. Il y a 17 articles, pas 17K. Je doute qu'il y aurait une différence dans le calendrier pour ce qui pourrait apparaître avec moins de millions de «animaux de compagnie chargés», si même alors. Il doit faire une classe BinarySearch, faire toutes sortes de vérifications d'exécution, faire * plus * classes, etc. Considérant que cela le rend plus compliqué que la solution simple et claire, pourquoi le faire? –

+0

@Andrew Backer: 'BinarySearch' n'est pas une classe. C'est une méthode de Array (ainsi que 'List ') et il ne crée aucun objet supplémentaire. En outre, toute la complexité est encapsulée dans l'implémentation .NET.Si nous devions écrire notre propre algorithme de recherche binaire, je serais d'accord avec vous - mais pourquoi ne pas utiliser quelque chose déjà fourni par la BCL? Gardez à l'esprit qu'une partie de la valeur de la réponse aux questions est que les gens qui envisagent cela dans le futur peuvent aider à trouver des solutions à leurs propres problèmes. Démontrer des approches alternatives a donc son propre mérite. – LBushkin

2

je prendrais Mark Byers répondre un peu plus loin. Depuis est un peu déroutant (je ne sais plus quel est int qui) font plutôt une liste triée des

SortedList<UserLevel> 

cette façon, vous pouvez définir beaucoup plus que juste un nombre requis de points d'expérience à chaque niveau. Vous pouvez également attribuer un nom, par exemple «Super niveau Uber Elite» et peut-être même un message de bienvenue personnalisé à chaque niveau.

2

Si l'algorithme d'expérience peut être réduite à une fonction, il doit utiliser le calcul fonctionnel, à savoir:

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

Cependant votre imbriqué si est au-dessus ne semblent pas appliquer à une courbe de fonction, il est?opérateur:

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

Que diriez-vous d'une formule simple, basée sur une fonction logarithmique?

Quelque chose comme

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