Voting

Category

real language

Bookmarking

Del.icio.us Digg Diigo DZone Earthlink Google Kick.ie
Windows Live LookLater Ma.gnolia Reddit Rojo StumbleUpon Technorati

Language Objective-C

Date:04/20/05
Author:Dan Christiansen
URL:n/a
Comments:7
Info:n/a
Score: (2.85 in 147 votes)
/*
 * 99 Bottles of Beer written in Objective-C for Mac OS X.
 * Should work on most OpenStep environments as well.
 *
 * Please note that since Objective-C is a superset of C, all
 * C versions are valid Objective-C as well. Therefore, this
 * version is written in fancy OO, and using NSLog rather than
 * printf for optimum uglyness.
 *
 * Compiles on Mac OS X with "gcc -framework Foundation 99Bottles.m"
 *
 * (c) 2002 Dan Christiansen
 */

#import <Foundation/Foundation.h>

@class BeerBottle;
@class BeerWall;

@interface BeerWall : NSObject
{
    NSMutableArray *bottles;
}
+ (BeerWall *)wallWithBottles:(int)nbottles;
- (int)bottles;
- (BeerBottle *)getBottle;
- (void)throwParty;
@end

@interface BeerBottle : NSObject
{
    BOOL full;
}
- (void)chug;
@end

@implementation BeerWall
- (id)initWithBottles:(int)nbottles
{
    self = [super init];

    bottles = [NSMutableArray arrayWithCapacity:99];

    int i;
    for (i = 0; i < 99; i++) {
        [bottles addObject:[[[BeerBottle alloc] init] retain]];
    }

    return self;
}

+ (BeerWall *)wallWithBottles:(int)nbottles
{
    return [[BeerWall alloc] initWithBottles:nbottles];
}

- (int)bottles
{
    return [bottles count];
}

- (BeerBottle *)getBottle
{
    BeerBottle *bottle = [bottles lastObject];
    [bottles removeLastObject];
    [bottle release];
    return [bottle autorelease];
}
- (void)throwParty
{
    /* Objective-C is only supposed to handle 63 recursive calls - we do 99.
    * Life's a bitch.
    */

    switch([self bottles]) {
        case 1:
            NSLog(@"1 bottles of beer on the wall, 1 bottles of beer,");
            NSLog(@"Take one down pass it around,");
            [[self getBottle] chug];
            NSLog(@"No bottles of beer on the wall.",
                  [self bottles], [self bottles]);
            NSLog(@"");
            break;
        default:
            NSLog(@"%d bottles of beer on the wall, %d bottles of beer,",
                  [self bottles], [self bottles]);
            NSLog(@"Take one down pass it around,");
            [[self getBottle] chug];
            NSLog(@"%d bottles of beer on the wall.",
                  [self bottles], [self bottles]);
            NSLog(@"");
            [self throwParty];
            break;
    }

    return;
}
@end

@implementation BeerBottle
- (id)init
{
    self = [super init];
    srand(time(0));
    full = YES;
    return self;
}

- (void)chug
{
    if (full) {
        if (rand()/(double)RAND_MAX < 0.025)
            NSLog(@"BUUUUUUUUURP!");
        full = NO;
    } else {
        printf("WTF!? This bottle's empty!!!\n");
    }
}
@end

int main()
{
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

    [[BeerWall wallWithBottles:99] throwParty];

    [pool release];
}

Download Source | Write Comment

Alternative Versions

Comments

>>  Tom9811 said on 09/21/05 17:40:04

Tom9811 Wow -- I never saw a tripple Memleak!

>>  Jean said on 05/02/06 18:37:03

Jean I don't understand
NSLog(@"No bottles of beer on the wall.",
[self bottles], [self bottles]);

there is no need for [self bottles], [self bottles] because in the string above, you do not have any %d.
Would this code complie correctly?

>>  Joshua Pennington said on 07/07/06 03:56:22

Joshua Pennington Jean:

Yes, it would still compile. It's a variable length argument function, past the NSString* formatting argument.

http://c-faq.com/varargs/index.html

>>  Greg Weston said on 08/31/06 23:03:48

Greg Weston Nits:

In initWithBottles, the alloc/init pair will create an object with retainCount == 1. This object is then sent a retain message (increasing the count to 2) and then stored in a container that increases the retain count on its own (now 3). This would be better with the explicit retain replaced by autorelease. Best would be to have BeerBottle offer to a factory method that returns an autoreleased bottle.

Now in getBottle, the removeLastObject message to the bottle container will reduce the retain count (to 2). Then there's an explicit release (down to 1) and the autorelease which will cause a release (down to zero and deallocation - as far as we care) at the end of the event loop. So unexpectedly it doesn't leak, but it's a fairly goofy way to go about it.

I would've gone for a loop instead of recursion and moved srand to an +initialize method.

>>  Brett said on 01/05/07 05:46:44

Brett Three things:

1: NSLog(@"%d bottles of beer on the wall.",
[self bottles], [self bottles]);
1 %d, 2 arguments

2. NSLog(@"1 bottles of beer on the wall, 1 bottles of beer,";);
1 bottles?

3. printf("WTF!? This bottle's empty!!!\n";);
No NSLog here?

>>  Joe said on 03/16/08 21:58:51

Joe This code sucks! Please learn the language before doing this.

>>  myName said on 06/28/09 01:33:18

myName If you copy and paste, be careful. This thing is full of issues.

Download Source | Write Comment

Add Comment

Please provide a value for the fields Name, Comment and Security Code.
This is a gravatar-friendly website.
E-mail addresses will never be shown.
Enter your e-mail address to use your gravatar.

Please don't post large portions of code here! Use the form to submit new examples or updates instead!

Name:

eMail:

URL:

Security Code:
  
Comment: