2010-06-01 8 views
6

Actualmente estoy trabajando en un servidor de emulación para un juego basado en cliente flash, que tiene un "sistema de mascotas", y me preguntaba si habría una forma más sencilla de verificar el nivel de mascotas especificadas.Método más simple/más eficiente de anidar si ... ¿otro flujo?

código actual:

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

Sí, soy consciente de que he experiencia misspelt, que había cometido el error en una función anterior y no había tenido tiempo de actualizar todo.

+15

No hay manera de que esto no es una cuestión broma. –

+1

En caso de que no lo sepa (no diciendo que no está ... simplemente tratando de ser útil), "actualizar todo" no es un proceso oneroso. Haga clic con el botón derecho en "Expirience"> Refactorizar> Cambiar nombre. Bueno para ir ... principalmente (las vistas no se actualizarán). –

+2

@George - o alguien lee TDWTF para las muestras de código ... – GalacticCowboy

Respuesta

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; 

Editar: alteración de utilizar la sugerencia de Bradley Mountford.

+0

Esta es probablemente la forma más escalable. – Puppy

+4

En lugar del retorno 17 para el retorno, es probable que desee devolver levelCuttoffs.size para que se escale dinámicamente. –

+0

Sí, esta parece ser la mejor solución para mi problema por ahora, ya que solo necesito devolver enteros, no cadenas. Gracias TreDubZedd. – Scott

22

Use un SortedList<int, int> y repítalo hasta que encuentre un valor que sea mayor que el valor que está buscando. Puedes hacerlo usando una iteración simple como en la respuesta que ya has aceptado. O se puede hacer elegantemente usando LINQ (a un costo de rendimiento leve):

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

Tenga en cuenta que el almacenamiento del 'nivel' en realidad no es estrictamente necesario como se puede derivar desde el índice del elemento de la lista. Puede ser ventajoso utilizar un simple List<int> que se ordena en su lugar para evitar errores en los que accidentalmente se pierde un nivel, como en la solución que ya ha aceptado.

Si quiere un mejor rendimiento puede usar List.BinarySearch, pero creo que la complejidad adicional no vale la pena a menos que tenga un perfil de rendimiento y descubra que este es el cuello de botella.

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

de hecho, mi solución también. +1 – user29964

+0

Definitivamente. Esto se llama un enfoque impulsado por tablas. Lo que tienes ahí es un montón de datos que has escrito como declaraciones de control. Escríbalo como datos en su lugar. –

+0

¿Tal vez corregir la ortografía de su variable? Me parece tan descuidado. – ChaosPandion

2

Vas de la más inclusiva a la más exclusiva. Si vas en la otra dirección, no necesitas todo el anidado.

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

Alternativamente, use este mismo enfoque con una instrucción Switch en lugar de todas las declaraciones if ... else. – AllenG

+2

@AllenG: la sentencia 'switch' de C# no admite rangos IIRC. – kennytm

+1

Ni siquiera necesita el 'else' – Patrick

4

@ La sugerencia de Mark es razonable. También se podría invertir el orden de la evaluación de la experiencia de un-nido del IFS:

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

pero probablemente sólo tiene que utilizar un C# matriz regular y el método BinarySearch, que puede devolver el índice del elemento coincidente o el complemento de la menor elemento que es mayor que el valor que ha buscado de 2:

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 es O (log n) y considerando que las marcas de nivel son corregido, esto funcionará mejor que simplemente iterar una lista de ifs o una lista de marcas de nivel. – David

+0

-1. Hay 17 artículos, no 17K. Dudo que haya una diferencia en el momento para esto que podría aparecer con menos de millones de 'mascotas cargadas', si es que incluso entonces. Tiene que hacer una clase BinarySearch, hacer todo tipo de comprobaciones de tiempo de ejecución, hacer * más * clases, etc. Teniendo en cuenta que lo hace más complicado que la solución simple y clara, ¿por qué hacerlo? –

+0

@Andrew Backer: 'BinarySearch' no es una clase. Es un método de Array (así como 'List ') y no crea ningún objeto adicional. Además, toda la complejidad está encapsulada en la implementación de .NET.Si tuviéramos que escribir nuestro propio algoritmo de búsqueda binaria, estaría de acuerdo con usted, pero ¿por qué no utilizar algo que ya proporciona el BCL? Tenga en cuenta que parte del valor de responder preguntas es que las personas que lo vean en el futuro pueden ayudar a llegar a soluciones para sus propios problemas similares. De modo que demostrar enfoques alternativos tiene su propio mérito. – LBushkin

2

me tomaría Marcos Byers responder a un paso más allá. Dado que es ligeramente confuso (me olvido, que es la que int) en lugar de hacer una lista ordenada de

SortedList<UserLevel> 

De esa manera se puede definir mucho más que un número requerido de puntos de experiencia a cada nivel. también puede asignar un Nombre, es decir, "Uber Elite Super Level" y tal vez incluso un mensaje de bienvenida personalizado en cada nivel.

2

Si el algoritmo de experiencia puede ser reducida a una función, se debe utilizar el cálculo funcional, es decir:

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

Sin embargo, su anidada si está por encima no parecen aplicarse a cualquier curva de función, no es el?operador:

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

¿Qué tal una fórmula simple, basada en una función logarítmica?

Algo así como

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