Gold Challenge - description method that computes


#1

Here is my solution for the description printing portion of the Chapter 2 Gold Challenge. It uses recursion to crawl the main BNRContainer, which contains an array of any combination of BNRItem and BNRContainer objects. Containers have a name and price. Totals are shown for all containers plus contents and all calculations are done in the description method.

First the formatted output:

[code]2012-07-16 12:41:22.010 RandomPossessions[1001:403]

CONTAINER: Backpack VALUE: $300
Fluffy Mac (3A6T4): Worth $30, recorded on 2012-07-16 17:41:22 +0000
Shiny Spork (8S3I1): Worth $77, recorded on 2012-07-16 17:41:22 +0000
Rusty Spork (4F6F9): Worth $65, recorded on 2012-07-16 17:41:22 +0000
Fluffy Spork (1P5F4): Worth $29, recorded on 2012-07-16 17:41:22 +0000

 CONTAINER: Camera Bag   VALUE: $400
   Fluffy Bear (3R2Q6): Worth $88, recorded on 2012-07-16 17:41:22 +0000
   Rusty Bear (4X7P8): Worth $38, recorded on 2012-07-16 17:41:22 +0000
   Shiny Mac (7E4L1): Worth $77, recorded on 2012-07-16 17:41:22 +0000
   Shiny Bear (8K9Y2): Worth $35, recorded on 2012-07-16 17:41:22 +0000
   Rusty Bear (5E2Z1): Worth $42, recorded on 2012-07-16 17:41:22 +0000
  TOTAL VALUE of Camera Bag and contents: $680

Fluffy Spork (8J8T0): Worth $94, recorded on 2012-07-16 17:41:22 +0000

 CONTAINER: Purse   VALUE: $200
   Rusty Spork (2F9Z7): Worth $40, recorded on 2012-07-16 17:41:22 +0000
   Rusty Bear (8G5V6): Worth $99, recorded on 2012-07-16 17:41:22 +0000
   Shiny Spork (3P9B1): Worth $10, recorded on 2012-07-16 17:41:22 +0000
   Rusty Mac (6R5C1): Worth $93, recorded on 2012-07-16 17:41:22 +0000
   Fluffy Spork (3E4O0): Worth $1, recorded on 2012-07-16 17:41:22 +0000  

      CONTAINER: Wallet   VALUE: $100
        Rusty Spork (8Q2U8): Worth $73, recorded on 2012-07-16 17:41:22 +0000
        Shiny Spork (5Y2V3): Worth $40, recorded on 2012-07-16 17:41:22 +0000
       TOTAL VALUE of Wallet and contents: $213

  TOTAL VALUE of Purse and contents: $656

TOTAL VALUE of Backpack and contents: $1931
[/code]

And the description method from BNRContainer.m:

- (NSString *)description
{
    // Initialize totals array if we are at the top level of the object tree
    if (indentLevel == 0) {
        for (int i = 0; i < 100; i++) {
            containerTotals[i] = 0;
        }
    }
    indentLevel++;
    
    NSString *descriptionString;
    NSString *indentString = [NSString stringWithFormat:@"\n"];
    
    for (int i = 1; i < indentLevel; i++) {
        indentString = [NSString stringWithFormat:@"%@     ", indentString];
    }
    
    containerTotals[indentLevel] += containerValueInDollars;
    
    descriptionString = [NSString stringWithFormat:@"\n%@CONTAINER: %@   VALUE: $%d",
                                          indentString, name, containerValueInDollars];
    
    for (id item in [self subitems]) {

        // If the current item is BNRItem then we want to indent now and need to add the item Value
        // to the appropriate slot in the totals array at index indentLevel.  
        if ([item isMemberOfClass:[BNRItem class]]) {
            descriptionString = [NSString stringWithFormat:@"%@%@", descriptionString, indentString];
            containerTotals[indentLevel] += [item valueInDollars];
        } 
        
        // The print formatting for the BNRItem / BNRContainers is determined by the system based on the
        // subclass type and it's description method.  The recursion bit comes in when we are trying to format
        // a child BNRContainer, which pushes another copy of this description method on the stack.
        descriptionString = [NSString stringWithFormat:@"%@  %@", descriptionString, item];
    }
    
    // When control arrives here we have iterated thru all array objects of the current BNRContainer
    // so it is time to show a total
    descriptionString = [NSString stringWithFormat:@"%@%@ TOTAL VALUE of %@ and contents: $%d\n", 
                                      descriptionString, indentString, name, containerTotals[indentLevel]];
            
    // Wrapping up this BNRContainer, we take the total Value and add it to the parent level.  
    containerTotals[indentLevel - 1] += containerTotals[indentLevel];

    // Then clear the computed Value for this index level to prepare for possible siblings.
    containerTotals[indentLevel] = 0;
    
    // back up an index / indent level to the parent
    indentLevel--;
    
    return descriptionString;
}

Notes:
Initialize indentLevel to zero in BNRContainer init.

Define these as BNRContainer class objects (above @implementation):

int indentLevel;
int containerTotals[100];

Yes there should be some array bounds checking and there is plenty of room for improvement but this seems to get the job done.