Click here to Skip to main content
15,884,013 members
Please Sign up or sign in to vote.
4.00/5 (2 votes)
See more:
I was making a project just to train a bit in C# (I'm a beginner), but I ran into a problem. (I did it on console so I didn't have to make a whole design again)
I wanted to have specific types of planets, and make some of them habitable and some of them uninhabitable. (It's probably a really stupid mistake)

But right now the console shows that some types aren't habitable while they are not in the list of uninhabitable types. (I skipped the code that isn't important for now)

C#
class Planet
    {
        public biomes biome; 
        public bool isHabitable = true; 
        public Planet()
        { 
            biome = getBiome(); 
            biomes notHabitable = biomes.Radiated | biomes.Barred | biomes.Dead | biomes.In                                  ferno | biomes.Toxic | biomes.Frozen | biomes.Glacial;    
            //if ((notHabitable & biome) == biome) { isHabitable = false; }                            // I tried both of these if-statements, but they didn't work
            if (notHabitable.HasFlag(biome)) { isHabitable = false; }        
            else { isHabitable = true; } 
        }
 
        static readonly Random rd = new Random();
        static T RandomEnumValue<T>()
        {
            return Enum.GetValues(typeof(T)).Cast<T>().OrderBy(x => rd.Next()).FirstOrDefault();
        }  
        private biomes getBiome()
        {
            return RandomEnumValue<biomes>();
        } 
    } 
    [FlagsAttribute]
    public enum biomes : long
    {                                              
        Radiated = 0x0, 
        Barred = 0x1, 
        Dead = 0x2,    
        Inferno = 0x4, 
        Dune = 0x8, 
        Desert = 0x16, 
        Minimal = 0x32, 
        Toxic = 0x64,   
        Savannah = 0x128, 
        Steppe = 0x256, 
        Tundra = 0x512,                     
        Swamp = 0x1024, 
        Jungle = 0x2048, 
        Forest = 0x4096,
        Frozen = 0x8192,
        Ocean = 0x16384,
        Terran = 0x32768,
        Glacial = 0x65536
    }



     class Program
    {
        static bool WritePlanet()
        {
            Planet pl = new Planet();

            Console.WriteLine("Planet biome: " + pl.biome.ToString());
            Console.WriteLine("Habitable: " + pl.isHabitable);
            Console.WriteLine("Press [\\] + enter to generate a new planet");

            if (Console.ReadLine() == "\\")
            {
                Console.Clear();
                WritePlanet();
                return true;
            }
            
            else
            {
                return false;
            }
        }


        static void Main(string[] args)
        {
            try { WritePlanet(); }
            catch (Exception ex) { Console.WriteLine("Error" + ex); Console.ReadLine(); } 
        }
    } 
Posted
Updated 1-Jan-14 9:34am
v3
Comments
ZurdoDev 1-Jan-14 15:23pm    
Where? What line of code is not working as you expect?
[no name] 1-Jan-14 15:28pm    
It is just not showing the right thing (for example "Planet biome: Forest", "Habitable: false"), and I don't know why (again, it is probably just a stupid mistake)
ZurdoDev 1-Jan-14 15:32pm    
Put a breakpoint and debug it and you should find out what is happening.
[no name] 1-Jan-14 15:36pm    
What exactly does a breakpoint do?
ZurdoDev 1-Jan-14 16:00pm    
You can watch what is happening and find the issue. In this case, if Solution 1 is correct, you would see that immediately upon instantiation your values were not what you expected them to be.

For a beginner, this is not so silly question, at least you formulated it correctly, which is so rare these days, my special thanks for that.

Your idea to use bit-mapped enumeration type to describe the planet status in a compact and well-supportable way is good. Only the declaration could be improved in this way:
C#
internal enum Biomes : ushort
{                                              
        Radiated = 1 << 0, 
        Barred = 1 << 1, 
        Dead = 1 << 2,   
        Inferno = 1 << 3, 
        Dune = 1 << 4,
        //...
}
I hope you got the idea. Also note the use of the unsigned type for underlying integer type, which you can also just skip, in most cases. I also capitalize the name to meet (good) Microsoft naming recommendations (you were correct to make it a plural noun).

Now, let's talk about your bug. You test the bits incorrectly. This is how it can be done:
C#
bool isRadiated = (biome & Biomes.Radiated) > 0;
boole isBarred = (biome & Biomes.Barred) > 0;
// are you getting the idea?
//...
biomes notHabitable = isRadiated | isBarred /* ... and so on; you could write it shorter... */;

Well, it was quite an obvious bug, especially if you pay attention that you did not even use biome value. Well, such things happen, especially at first. :-)

I would advise your to learn bit operations really well: http://msdn.microsoft.com/en-us/library/6a71f45d.aspx[^].

Also, for really advanced use of enumerations (with bit maps or not), please see my three articles on this topic: http://www.codeproject.com/Articles/SAKryukov#articles[^].

And finally, that "radiated" does not mean that life is impossible. Some life form can withstand harsh radiation levels even on Earth. This is biology, not programming. For a home exercise, try to answer a different question: "Is the Earth habitable?". This question is not so easy as it may seem. For example, the look at many posts at this forum may help to conclude that the Earth might be habitable, but the presence of intellectual life could be a matter of controversies. :-)

Good luck. Happy New Year!

—SA
 
Share this answer
 
v4
Comments
CHill60 1-Jan-14 16:07pm    
My 5 - for the excellent answer, for praising the quality of the question (as you say - rare) but mostly for making me laugh out loud ... "the Earth might be habitable, but the presence of intellectual life could be a matter of controversies" :-)
Sergey Alexandrovich Kryukov 1-Jan-14 16:18pm    
Thank you very much. (And this is not 100% of a joke. It depends on what you would consider "intellectual". If you look at the all those wars and other disasters caused by human beings, it could also make the matter of controversies. Piece be with your.)
Happy New Year!
—SA
Ron Beyer 1-Jan-14 16:14pm    
I +5'd. Happy New Year.
Sergey Alexandrovich Kryukov 1-Jan-14 16:22pm    
Thank you, Ron.
—SA
BillWoodruff 1-Jan-14 20:35pm    
+5 Excellent
I know what's happening...

Your enum is defined as flags, but you are incorrectly assigning values to the flags, it should be:

C#
[Flags]
public enum biomes : long
    {                                              
        Radiated = 0x0, 
        Barred = 0x1, 
        Dead = 0x2,    
        Inferno = 0x4, 
        Dune = 0x8, 
        Desert = 0x10, 
        Minimal = 0x20, 
        Toxic = 0x40,   
        Savannah = 0x80, 
        Steppe = 0x100, 
        Tundra = 0x200,                     
        Swamp = 0x400, 
        Jungle = 0x800, 
        Forest = 0x1000,
        Frozen = 0x2000,
        Ocean = 0x4000,
        Terran = 0x8000,
        Glacial = 0x10000
    }


The hex values you were giving were actually combinations of other values. You don't multiply by 2 (you would if you were assigning decimal values), but when doing hex values, 8 * 2 = 0x10, not 0x16 for example. 0x16 is a combination of other values you probably didn't want.

OR you could just remove the 0x from the value, also, you should not use 0x0 as a flag value, since it literally means "no flags", 0x0 should always be "None", and start your values at 0x01.

Edit: here is how I would change it to make it easier to add habitable/inhabitable planets:

C#
[Flags]
public enum Biomes
{
    Habitable = 0x01,
    Uninhabitable = 0x02,
    Barred = 0x04 | Uninhabitable,
    Dead = 0x08 | Uninhabitable,
    Radiated = 0x10 | Uninhabitable,
    Inferno = 0x20 | Uninhabitable,
    Toxic = 0x40 | Uninhabitable,
    Frozen = 0x80 | Uninhabitable,
    Glacial = 0x100 | Uninhabitable,
    Dune = 0x200 | Habitable,
    Desert = 0x400 | Habitable,
    Minimal = 0x800 | Habitable,
    Savannah = 0x1000 | Habitable,
    Steppe = 0x2000 | Habitable,
    Tundra = 0x4000 | Habitable,
    Swamp = 0x8000 | Habitable,
    Jungle = 0x10000 | Habitable,
    Forest = 0x20000 | Habitable,
    Ocean = 0x40000 | Habitable,
    Terran = 0x80000 | Habitable
}


Which makes it very clear from the enum (instead of defining it in the class) what is habitable and uninhabitable, and is a very good use for flags. You can also use shift operators like Sergey said in Solution 2, however I find that they are hit and miss as far as understand-ability. I prefer to use straight hex but your preference is your call.

Now your flag checking will work with any planet since you've defined them as a combination of flags. I think this is a better way than originally defined, since you only have to check for the Habitable or Uninhabitable flag to see if a planet is one or the other, rather than check for a certain combination of planets. This is also very maintainable (changing, for example, the Minimal planet from Habitable to Uninhabitable only requires a small change to the enum).
 
Share this answer
 
v4
Comments
Sergey Alexandrovich Kryukov 1-Jan-14 15:49pm    
Correct, that explains the bug. I voted 4, because you could improve the enum declaration (base integer type should rather be unsigned, or could be omitted, but long is pointless). I have done it and suggested other improvements in Solution 2, and maybe my code of bit extracting could be a bit easier to understand.

Also, None may or may not be needed.

Happy New Year!

—SA
Ron Beyer 1-Jan-14 16:13pm    
Thanks Sergey, I updated my answer with what I feel is a better solution for the problem at hand and a better use of enumerations as bitwise flags, and more maintainable. This is typically how I define my flag enumerations.
CHill60 1-Jan-14 16:18pm    
5'd - I do like that trick with the flags and for me it's more intuitive (and therefore easier to hand over when I leave a contract)
Ron Beyer 1-Jan-14 16:28pm    
Thanks!
Sergey Alexandrovich Kryukov 1-Jan-14 16:22pm    
Up-voted even more for new nice feature which takes only one bit in implementation (:-) and nicely moves the issue from code to data definition. :-)
—SA

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900