0

I am very new to Objective C, and working on a project and I am struggling with the pass-by-reference, among other things which is likely obvious in my code. If someone could break it down for me in regard to my code I would appreciate it.

@interface Player : NSObject
{

}

//@property
@property (nonatomic, readwrite) NSString* name;
@property (nonatomic, readwrite) NSInteger *humanPoints;
@property (nonatomic, readwrite) NSInteger *computerPoints;
@property (nonatomic, readwrite) BOOL isWin;
@property (nonatomic, readwrite) BOOL isLoss;
@property (nonatomic, readwrite) BOOL isPoints;
@property (nonatomic, readwrite) NSInteger rollAgain;
//Methods
-(id) init;
-(void) RollFirstDie: (NSInteger) firstDie andSecondDie: (NSInteger) secondDie andThirdDie: (NSInteger) thirdDie;
-(NSInteger) GetRandomRoll;
-(BOOL) DoRoll; 


@end

with its .m

#import "Player.h"


@implementation Player

@synthesize name;
@synthesize humanPoints;
@synthesize computerPoints;
@synthesize isWin;
@synthesize isLoss;
@synthesize isPoints;
@synthesize rollAgain;

-(id) init
{
    self = [super init];

    if (self!=NULL)
    {
        name = @"human";
        humanPoints = 0;
        computerPoints = 0;

    }
    return self;
}

-(void)RollFirstDie: (NSInteger) firstDie andSecondDie: (NSInteger) secondDie andThirdDie: (NSInteger) thirdDie
{

    firstDie = arc4random()% 6+1;
    secondDie = arc4random()% 6+1;
    thirdDie = arc4random()% 6+1;

}

-(NSInteger) GetRandomRoll
{


    die1 = firstDie;
    die2 = secondDie;
    die3 = thirdDie;

    return die1, die2, die3;
}

-(BOOL) DoRoll
{
    NSLog(@"Human Roll Dice?[Y/N] ");
    scanf(" %ld", &rollAgain);

    return rollAgain;
}

where the most trouble I have is with the second .h/.m:

#import <Foundation/Foundation.h>
#import "Player.h"

@interface DiceGame : NSObject
{
    NSInteger die1;
    NSInteger die2;
    NSInteger die3;

    //Player* human
    //Player* cpu
    BOOL rollAgain;
}


//Methods
-(id) init;
-(void) Play;
-(void) CheckRollConditions;
-(void) ResetDice;
-(void) DisplayWinner;
-(void) TakeTurn;

@end

.m

#import "DiceGame.h"

@implementation DiceGame

-(id) init
{
    self = [super init];

    if (self!=NULL)
    {
        die1 = 0;
        die2 = 0;
        die3 = 0;

    }
    return self;
}

-(void) Play
{
    [self TakeTurn];
    if (name isEqual @"human")
    {
        [self RollFirstDie: firstDie andSecondDie: secondDie andThirdDie: thirdDie];
        [self CheckRollConditions];
        if (rollAgain == 1)
        {
            [self RollFirstDie: firstDie andSecondDie: secondDie andThirdDie: thirdDie]
            [self CheckRollConditions];
        }
        name = @"computer";
    }
    [self ResetDice ];
    while (computerPoints == 0)
    {
        [self RollFirstDie: firstDie andSecondDie: secondDie andThirdDie: thirdDie]
        [self CheckRollConditions];
        while (computerPoints == humanPoints)
        {
            [self RollFirstDie: firstDie andSecondDie: secondDie andThirdDie: thirdDie]
            [self CheckRollConditions];
        }
    }

    [self DisplayWinner ];


    [self GetRandomRoll];


}
-(void) CheckRollConditions
{
    //Three of a Kind
    if ((die1 == die2) && (die1 == die3))
    {
        NSLog(@"You got 3 of a kind, you win!");

    }
    //Two of a Kind
    else if ((die1 == die2) || (die2 == die3) || (die1 == die3))
    {
        if (die1 == die2)
        {
            if (Player.name isEqual @"human")
            {
                humanPoints = die3;
            }
            else
            {
                computerPoints = die3;
            }


        }
        else if (die1 == die3)
        {)
            if (name isEqual @"human")
            {
                humanPoints = die2;
            }
            else
            {
                computerPoints = die2;
            }
        }
        else
        {
            if (name isEqual @"human")
            {
                humanPoints = die1;
            }
            else
            {
                computerPoints = die1;
            }
        }
        if (name isEqual @"human")
        {
            NSLog(@"You got a pair, your score is: %ld", humanPoints);
        }
        else
        {
            NSLog(@"Computer got a pair, their score is: %ld", computerPoints);
        }

    }
    //Lose Sequence
    else if (((die1 != die2) && (die1 != die3) && (die2 != die3)) && ((die1 <= 3) && (die2 <= 3) && (die3 <= 3)))
    {
        NSLog(@"Game Over, %@ Lose!", name);

    }
    //Win Sequence
    else if (((die1 != die2) && (die1 != die3) && (die2 != die3)) && ((die1 > 3) && (die2 > 3) && (die3 > 3)) && ((die1 <= 6) && (die2 <=6) && (die3 <= 6)))
    {
        NSLog(@"Congratulations! %@ Wins!", name);

    }

    //No win or lose
    else
    {
        while (name isEqual @"human")
        {
            NSLog(@"You did not get a sequence or a pair");
            NSLog(@"Human, roll again?[y/n]");
            scanf("%ld", &rollAgain);break;
        }

    }


}
-(void) ResetDice
{
    die1 = 0;
    die2 = 0;
    die3 = 0;
}
-(void) DisplayWinner
{
    if (computerPoints > humanPoints)
    {
        NSLog(@"Computer had a higher score");
    }
    else
    {
        NSLog(@"Human had a high score");
    }
}
-(void) TakeTurn
{

        if ([name isEqual: @"human"])
        {
            [self RollFirstDie: firstDie andSecondDie: secondDie andThirdDie: thirdDie]
            NSLog(@"Rolling...");
            NSLog(@"You rolled: ");
            NSLog(@"%ld, %ld, %ld", die1, die2, die3);

        }
        else
        {

            {
                [self RollFirstDie: firstDie andSecondDie: secondDie andThirdDie: thirdDie]
                NSLog(@"Rolling...");
                NSLog(@"Computer rolled: ");
                NSLog(@"%ld, %ld, %ld", die1, die2, die3);
            }
        }

}


@end

and main:

#import <Foundation/Foundation.h>
#import "DiceGame.h"


int main(int argc, const char * argv[])
{
    @autoreleasepool
    {
        DiceGame* roll = [[DiceGame alloc] init];


        [roll Play];


    }
    return 0;
}

So what's happening is that the DiceGame.m does not recognize anything from the Player class. I know what I want the code to do, but I am struggling to get it there. (and because it's already a very long post, I have left out some of the later methods that I was not having problems with)

Edit: Thank you guys for all your help, I have update this with the full code, however you're right it does not compile which is what I am needing help on now. The Pass By Reference was less of a problem than I originally thought it was. The errors I am getting now I believe are part of the same issue: 1. Use of undeclared identified "variableName" (die1/die2/die3 etc). I have them define in a separate method but I didn't think that should have been an issue? Not sure if I was wrong or I am missing something important there

  1. No visible @interface for 'DiceGame' declares the selector 'GetRandomRoll' (and others)

i think only one class can inherit from NSObject but I can't seem to figure how to fix my code to make that work

  • The code you have posted does not appear to even compile. If this is not the actual code you use then post the actual code. If you are getting error messages that do you do not understand then say what those messages are and what you don't understand and someone might be able to explain them to you. – CRD Feb 22 '16 at 09:18
  • Objective-C strings are objects, so they require object syntax when you send them messages. Things like `(name isEqual @"human)"` need to be `([name isEqual @"human"])` unless you want to confuse both the reader and the compiler. – Phillip Mills Feb 29 '16 at 14:22

3 Answers3

0

If this method :

-(void)RollFirstDie: (NSInteger) firstDie andSecondDie: (NSInteger) secondDie andThirdDie: (NSInteger) thirdDie

is the same method you call here:

[self RollFirstDie: (NSInteger*) firstDie andSecondDie: (NSInteger*) secondDie andThirdDie: (NSInteger*) thirdDie];

This is not a normal approach in Objective-C, (NSInteger*) firstDie is casting whatever in firstDie into a pointer of NSInteger, and if you are calling the same method it wont compile unless you do *(NSInteger*) firstDie (Assuming firstDie is a NSInteger)

But as I said, this might not what you wanted, if firstDie is just a NSInteger, you should just simply do:

[self RollFirstDie: firstDie andSecondDie: secondDie andThirdDie:thirdDie];

In this case firstDie, secondDie and thirdDie would be passed by value, since NSInteger is primitive type in objc. If you want to pass by reference, you should use NSNumber*.

Hope this helps.

lcl
  • 1,045
  • 11
  • 13
0

There are more issues than the call by reference of your question, but it is unclear whether the code posted is your actual code as it appears not to compile. So I'll just address call by reference and hope it helps.

Objective-C does call by reference the same way as C, and that means it doesn't directly support it - it is a do-it-yourself construction:

  1. When you call a function you pass the address of a variable;
  2. In the function declaration you declare the parameter type to be a pointer to the type of the parameter; and
  3. In the function body you access the variable using indirection

So for your roll three dice method the method would be (Note: all code typed directly into answer, expect little typos):

-(void) rollFirstDie:(NSInteger *)firstDie  // parameter type is
        andSecondDie:(NSInteger *)secondDie //  pointer to NSInteger
         andThirdDie:(NSInteger *)thirdDie
{
   *firstDie = arc4random_uniform(6) + 1;  // 1) must use indirection, *firstDie,
   *secondDie = arc4random_uniform(6) + 1; // to access variable
   *thirdDie = arc4random_uniform(6) + 1;  // 2) arc4random_uniform is better than
                                           // using modulus (%), see documentation
}

and the call would be:

[aPlayer rollFirstDie:&firstDie  // pass the address (&) of the variable
         andSecondDie:&secondDie
          andThirdDie:&thirdDie];

An alternative approach to DIY call-by-reference for returning multiple values is to use a struct, a struct is a simple record type which is passed by value. So for example you can define:

typedef struct
{
   NSInteger firstDie;
   NSInteger secondDie; 
   NSInteger thirdDie;
} ThreeDice;

to represent your three dice and then define your roll method to return a value of this type:

-(ThreeDice) rollThreeDice
{
   ThreeDice diceSet;
   diceSet.firstDie = arc4random_uniform(6) + 1;  // use <struct>.<field> to
   diceSet.secondDie = arc4random_uniform(6) + 1; // access each element
   diceSet.thirdDie = arc4random_uniform(6) + 1;
   return diceSet; // return the value
}

and your call becomes:

ThreeDice rollOne;
rollOne = [myPlayer rollThreeDice];

As you can see using a struct avoids taking addresses (&), declaring pointers (NSInteger *), and indirection (*firstDie).

HTH

CRD
  • 52,522
  • 5
  • 70
  • 86
0

In Objective-C, we use pointers for all objects, and thus when you are passing objects, you passing them by reference.

So, when you do something like NSString *str = @"hi!"; you are creating a pointer to an NSString object. Now, whenever you are passing str as a method argument, you are passing it by reference.

I see you are trying to do the same with NSInteger as well, but NSIntegers are not objects, but they are just typedef'ed to the int data type in C, and thus those are passed by value and you should not use the asterisk for those. You can just do this: NSInteger value = 4; It's important to keep an eye on whether something is an object or if it's just a primitive type or a struct.

I also noticed a couple of coding convention issues:

  • when you do self = [super init]; you can follow that with if(self) instead (I think NULL works the same but in ObjC we use nil).
  • method names are camelCase as opposed to TitleCase; we save TitleCase for class names

Hopefully that gets you sorted out!

Aaron
  • 879
  • 7
  • 18
  • Everything is pass by value. You can't "pass objects". You can pass pointers to objects, by value. – newacct Mar 02 '16 at 22:29