Search Unity

Issue converting BitArray to int

Discussion in 'iOS and tvOS' started by AdsySingle, Nov 28, 2011.

  1. AdsySingle

    AdsySingle

    Joined:
    Jan 5, 2011
    Posts:
    116
    I'm attempting to use a bit array as an alternative to a massive bunch of bools. Logic wise I'm having some trouble though.

    I have two bit arrays basically. One that is the overall state of internal achievements that have been unlocked, and another that is the state of achievements that have been unlocked since the last time the player went to the achievement screen in menu (so that I can play an animation of the achievements being unlocked, locks exploding or something like that).

    So in game these achievements are mainly based on combinations of collected items (picture MasterMind with the coloured pegs). The order matters as much as the items. So as I'm calculating the score I'm also sorting out if it was one of the achievement combinations. So I have the bit array set to all true and when I check the value of the first item in the combination I can eliminate any achievement combos that didn't start with this item (think flipping heads down in Guess Who?). Then at the end I either have none left at true, or just one, the index of which tells me which achievement was satisfied by that combo.

    My problem is when converting the final bit array to an int using the code below I'm getting a very strange number.

    Here's the code:
    Code (csharp):
    1.  
    2. int[] array = new int[1]; //create an int array of length one
    3. myBitArray.CopyTo(array,0); //copy the contents from the BitArray into the int array's first (and only) position
    4. Debug.Log("BitArray value is: " + array[0].ToString());
    5.  
    what I get out of this is -524287.

    Now I've debugged the individual values of myBitArray and they are all false except one true, which is the first one (so I'm expecting a result back of 1). As another interesting note my BitArray has a length of 19, and 19 1's in binary is 524287 (I have no idea how it can be negative, or why it would be copying as this when the BitArray is debugging out the correct true and false values).

    Any help would be greatly appreciated.

    Adsy
     
  2. Eric5h5

    Eric5h5

    Volunteer Moderator Moderator

    Joined:
    Jul 19, 2006
    Posts:
    32,401
    Are you sure?

    Code (csharp):
    1. var myBitArray = new BitArray(19);
    2. myBitArray.Set(0, true);
    3. var array = new int[1];
    4. myBitArray.CopyTo(array, 0);
    5. Debug.Log("BitArray value is: " + array[0].ToString());
    That creates a BitArray with a length of 19 with all false except for one true, and it prints 1. I'm not really sure why you're making an int array with a length of 1 and using CopyTo, however. Wouldn't you just use Get()?

    --Eric
     
  3. AdsySingle

    AdsySingle

    Joined:
    Jan 5, 2011
    Posts:
    116
    I'm creating an int array with length 1 for the same reason you did above. The CopyTo() function takes in an array of ints and copys the bits in the bit array to these ints. Since I have less than 32 all of mine will fit into a single int. This int is what I want to use since it's value can be compared to an enum to tell me which bit is on.

    I have done exactly what you have done in your code snippet, except instead of hard coding a bit array with true at index 0 I've reached that through my logic (since it could be any of them that are turned on).

    I'm very sure that I have debugged out the bit array and verified the contents.

    Code (csharp):
    1.  
    2. for(int i = 0; i < myBitArray.Count; ++i)
    3. {
    4.     Debug.Log("value at index " + i.ToString() + " is " + myBitArray.Get(i).ToString());
    5. }
    6.  
    this is giving true then 18 falses. The very next line is myBitArray.CopyTo(array, 0); (just as you have above) and then the debug line which is printing -524287.

    I could use Get() but I am trying to avoid looping through the bitarray until I find the bit that is on. Plus I want to be able to save the bitarray for all unlocked achievements as an int to save space.
     
  4. Eric5h5

    Eric5h5

    Volunteer Moderator Moderator

    Joined:
    Jul 19, 2006
    Posts:
    32,401
    Well, I did that because I just copied your code. I didn't really understand what you were doing exactly. What happens if you use the hard-coded BitArray code, as a test?

    --Eric
     
  5. AdsySingle

    AdsySingle

    Joined:
    Jan 5, 2011
    Posts:
    116
    OK, so the hard coded version worked. What have I missed. I don't understand why my original code isn't working. It's essentially exactly the same. The bit arrays have the same values, or at least they do when I debug them out like I did above. Yet the CopyTo seems to be giving me garbage. Feels like something uninitialised.
     
  6. Ntero

    Ntero

    Joined:
    Apr 29, 2010
    Posts:
    1,436
    For what you want, could you not get the same effect using the Flags Enum Attribute?
    http://msdn.microsoft.com/en-us/library/system.flagsattribute.aspx
    Code (csharp):
    1.  
    2. [System.Flags]
    3. public enum MyFlags
    4. {
    5. First = 1,
    6. Second = 2,
    7. Third = 4,
    8. ...
    9. Nineteenth = 2^19
    10. }
    11.  
    12. void MyFunc(MyFlags flaggedEnum)
    13. {
    14. if((flaggedEnum  ~MyFlags.Tenth) > 0)) //Anything is on except 10
    15. if(flaggedEnum  (MyFlags.First | MyFlags.Second) > 0) //If First or Second is enabled
    16. if(flaggedEnum > MyFlags.Fifth) //Something after the fifth is enabled
    17.  
    18.  
    19. //Also
    20. (newAchievements ^ oldAchievements)  //This would return a single Enum containing all achievements that are in New, but were not in Old
    21.  
    22. //And it's easy to cast:
    23. int enumContainer = (int)flaggedEnum;
    24. }
    25.  
    Using that you can do all sorts of complex comparisons and binary logic on the enumeration directly. Just remember to increment your Enum values by powers of 2. It means the Enumeration is castable to an int, and contains all relevant values in 1 place.

    Edit: As far as your situation, are you taking into account the Sign bit and the Endianness of the Int? (one bit is for sign, and sometimes internally the bytes can be forward or backward depending on platform). Get a 32 bit, BitArray and try each bit 1 at a time and record the values, then it shouldn't be hard to determine why 19 is -524287.

    Edit2: Also tryout a 31 sized BitArray, and double check the assumption that unused bits are set to 0 and not 1.
     
    Last edited: Nov 29, 2011
  7. AdsySingle

    AdsySingle

    Joined:
    Jan 5, 2011
    Posts:
    116
    That's fantastic. That looks like what I was trying to do anyway. In fact I already have an enum that uses the power of two values exactly like that so that I could compare the int to an enum to see if it was on. I have never even heard of these flagged enums.
    I'll check those out,
    thanks heaps.

    Adsy