• Bittle Tobby Lables (unregistered)

    ... so TRWTF is the lack of attention to code formatting details on case 10?

    No, it's a complete lack of inspiration as to what to map case 11 to.

  • Michael R (unregistered)
            default: returnData = "Frist";
            break; 
    
  • (nodebb) in reply to Bittle Tobby Lables

    Maybe one enemy has parts that drop off as you attack it that have to be spawned as smaller enemies. In that case, 11 kind of makes sense.

  • Chris (unregistered)

    I'm twinging at "Bell Pepper" having a space, but "OneGrape" does not.

  • Chris (unregistered)

    I remember a while back having no luck trying to get a colleague to see the value of using enums over strings. We were dealing with country names, where the business logic might change depending on the country specified in the data being processed. I was trying to convey how it easy it is to slip a typo into your code with strings e.g. if (country == "Eblonia"), instead of "Elbonia", but using an enum name prevents that from occurring. He couldn't see the point.

  • Duston (unregistered)

    If you get a few people in a room and everyone says "rutabaga" over and over again, it sounds like a crowded restaurant. Maybe that's what the coder was thinking?

  • Dave (unregistered) in reply to Chris

    Presumably it's because they originally used grapes and grape, then tried some kind of string search for 'grape' and got the wrong result

  • Zygo (unregistered)

    Well, you say game developers are not typically concerned with reusable code, but this thing is obviously borrowed from some fruit-oriented game with 12 enemy types, including one apparently very dangerous boss grape, and nobody enjoys writing serialization functions. Why reinvent the watermelon?

  • (nodebb)

    including one apparently very dangerous boss grape

    And we can tell it's dangerous because it's turned all the way up to ... eleven.

  • OldCoder (unregistered)

    What was wrong with just using an array? (Aside from the complete lack of validation, that is.) Am I missing something?

  • MaxiTB (unregistered) in reply to OldCoder

    In C# you use an enum (value type, usually derived from int) and just call the ToString() method. An array is an object type, it's slow and a waste of GC resources literally because it will end up just escalating in generations and the GC always have to make a pass over it - hence you want to avoid long living objects in general similiar to as you want to avoid allocing a lot of heap objects (aka reference types). With an enum the name is stored as type info meta data which the GC ignores by default.

    In other words enums are way more efficient in every way, they are best practice and readable and you can add even more type information with attributes like DisplayName without losing out on refactoring capabilities or general overall performance and efficiency.

  • Yikes (unregistered)

    O(n) where there could be O(1) makes me hiss. In C++, I think I'd just do map<int,string>, along with a reverse mapping (array for int->string is appealing, but makes it harder to delete a specific ID later down the line). Not really knowing about C#, I do kind of like the enum approach in that language, although if I really want the spaces in the strings, I'd have to add in a replace and manage a special character. Also, I imagine it must also be storing some mapping permanently in memory in order to enact the conversions, so I don't see how memory is being handled any more minimally.

    using System;
    
    class Program {
      enum EnemyType {
        Radish = 0,
        Tomato,
        Orange,
        Banana,
        Strawberry,
        Carrot,
        Watermelon,
        Grapes,
        Broccoli,
        Bell_Pepper,
        Coconut,
        OneGrape
      };
    
      public static string enemyIdNumToName(int intId) {
        if (EnemyType.IsDefined(typeof(EnemyType), intId)) {
          return ((EnemyType)intId).ToString();
        }
        else {
          return "UNDEFINED";
        }
      }
    
      public static int enemyIdNameToNum(string name) {
        if (EnemyType.IsDefined(typeof(EnemyType), name)) {
          return (int) Enum.Parse(typeof(EnemyType), name);
        }
        else {
          return -1;
        }
      }
    
      static void tryID(int intID) {
        string name = enemyIdNumToName(intID);
        int num = enemyIdNameToNum(name);
        Console.WriteLine("intID=" + intID + "  name=" + name + "  reverse id=" + num);
        
      }
      
      static void Main(string[] args) {
        tryID(11);
        tryID(12);
      }
    }
    
    
  • Barry Margolin (github) in reply to Yikes

    It's not O(n). Most compilers will optimize switch into a jump table. A good optimizer may even turn this whole function into an array reference.

  • Yikes (unregistered) in reply to Barry Margolin

    You're right! But I'll point out that while it runs in O(1), it's still O(n) code size!

  • Officer Johnny Holzkopf (unregistered) in reply to Zygo

    Maybe the game in question it's a crossover between "Commander Keen: Keen Dreams" and "Eat Them To Defeat Them". Plus zombies. And one grape, provided by J.-B. E. Zorg...

  • Chris (unregistered) in reply to Yikes

    We use annotations to give enums names for display. We then use helper methods for getting the name for an enum. Although I don't think that would be the best for performance in game code, as it uses reflection.

  • ismo (unregistered) in reply to Michael R

    The code initializes returnData in declaration so there is no need for default case handling.

  • Michael R (unregistered) in reply to OldCoder

    You must be new here. ;-)

  • RLB (unregistered)

    The one enemy I'm missing is a pointed stick.

  • Craig (unregistered) in reply to MaxiTB

    I think you've got the GC impact backwards. Rising in generations won't increase the GC cost, because the frequently-running GCs will ignore long-lived objects---that's the whole point of a generational GC is to optimize for scanning and reclaiming short-lived objects. The impact is more that if it ever gets released (which is unlikely in this case), it will be difficult and costly to convince the GC that it should reclaim the memory.

  • Altreus (unregistered)

    Makes me realise how valuable it is that some languages force you to cover the entire range of a data type in your switch statement, or it won't compile.

  • Allocator (unregistered) in reply to Yikes

    Using std::map for mapping short string to an integer, when you only have ~10 of these pairs, is the wrong way, actually. As weird as it might seem, a ladder of if-else will work much faster and will not allocate additional memory.

  • Gnasher729 (unregistered) in reply to Yikes

    It’s O(n) with n = 12 which makes it O(1). A switch statement is generated by the compiler, and it can be done wit a O(1) jump table, an O(log n) binary tree, or linear with six comparisons and 12 branches. The binary tree would tin in two nanoseconds.

Leave a comment on “Enumerating Your Plants”

Log In or post as a guest

Replying to comment #:

« Return to Article