My Bronze Challenge solution


#1

Hi
I solved this challenge with these changes, but I don’t know if they are the most correct, so I am going to put the solution and I hope you share yours

First, I created a NSMutableArray in the HypnosisView.h

@interface HypnosisView : UIView { NSMutableArray *colors; }

Secondly, I init this array with different colors in the initWithFrame

[code]- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];

colors = [NSMutableArray arrayWithObjects:[UIColor redColor], [UIColor blueColor], [UIColor grayColor], [UIColor blackColor], nil];
if(self) {
    [self setBackgroundColor:[UIColor clearColor]];
    
    
    [self setCircleColor:[UIColor grayColor]];
}

return self;

}[/code]

And finally, I change the colours in the for within drawRect

[code]for (float currentRadius = maxRadius; currentRadius > 0; currentRadius -= 20) {
int indexColor = rand() % [colors count];
[self setCircleColor:[colors objectAtIndex:indexColor]];

    [[self circleColor] setStroke];
    
    CGContextAddArc(ctx, center.x, center.y, currentRadius, 0.0, M_PI * 2.0, YES);
    
    CGContextStrokePath(ctx);
}[/code]

Be careful with the [[self circleColor] setStroke]. If you don’t move this line into the for, the color won’t change.

I chose this way because I wanted to have a list of “available colors” and take them of this list.


#2

Mine is similar to yours. I created a randomColor method to generate and return the random color:

[code]- (UIColor *)randomColor
{
NSArray *colorArray = [NSArray arrayWithObjects:
[UIColor blackColor], [UIColor blueColor], [UIColor brownColor],
[UIColor cyanColor], [UIColor grayColor], [UIColor greenColor],
[UIColor magentaColor], [UIColor orangeColor],[UIColor purpleColor],
[UIColor redColor], [UIColor yellowColor], nil];

UIColor *color = [colorArray objectAtIndex:(random() % [colorArray count])];
return color;

}
[/code]
Then I called the method inside the for loop from the drawRect: method:

[code]// Draw concentric circles from the outside in
for (float currentRadius = maxRadius; currentRadius > 0; currentRadius -= 20) {

    // Add a path to the context
    CGContextAddArc(ctx, center.x, center.y, currentRadius, 0.0, M_PI * 2.0, YES);
    
    // Bronze Challenge: Colors 
    [[self randomColor] setStroke];
    
    // Perform drawing instruction; removes path
    CGContextStrokePath(ctx);
}

[/code]


#3

Mine is a little different. I wonder if this comes from a background in scripting languages versus OO programming. This is all in HyponosisView.m:

First question: Would I be better off – or more correct – to have included this in the .h file instead?

I’m sure I could have used a set here, too, but I’m so array-trained that I can’t break those habits just yet.

Then, I just set up a counter and looped through:

[code]
// Draw concentric circles
int count = 0; // Initialize counter

for (float currentRadius = maxRadius; currentRadius > 0; currentRadius -= 20) {
    
    if (count == [circleColors count]) {    // Since array is 0-based, you pop an error if you test for greater than
        count = 0;  // We're at the end of the array, so start back at the beginning
    }
    
    [[circleColors objectAtIndex:count] setStroke];
    count++; // Only after the count is used as the array index can we ++ it
    
    //Add a path
    CGContextAddArc(ctx, center.x, center.y, currentRadius, 0.0, M_PI * 2.0, YES);
    
    // Perform drawing instructions, removes path
    CGContextStrokePath(ctx);
}[/code]

-Augie


#4

Mine is probably the laziest solution. I took “Make the circles appear in assorted colors”, to mean "When you shake the device - make the circles appear in assorted colors. Which means I just updated the motionBegan:withEvent method in HypnosisView.m like so:

[code]- (void)motionBegan:(UIEventSubtype)motion withEvent:(UIEvent *)event {
if (motion == UIEventSubtypeMotionShake) {
NSArray *colourChoice = [[NSArray alloc] initWithObjects:
[UIColor blackColor],
[UIColor darkGrayColor],
[UIColor lightGrayColor],
[UIColor grayColor],
[UIColor redColor],
[UIColor greenColor],
[UIColor blueColor],
[UIColor cyanColor],
[UIColor yellowColor],
[UIColor magentaColor],
[UIColor orangeColor],
[UIColor purpleColor],
[UIColor brownColor],nil];

    self.circleColor = [colourChoice objectAtIndex:arc4random() % [colourChoice count]];
}

}[/code]

Then each time the device gets shaken the colors change.


#5

Is there any way of doing this with help of the UIColor method colourwithred:green:blue:andalpha:?

tried making the green increase as the for loop progressed but couldn’t get it to work properly any one else had any luck?


#6

I chose to generate a random color in each iteration of the for loop rather than selecting from a pre-filled list. It looks pretty trippy. Here’s my code:

for (float currentRadius=maxRadius; currentRadius>0; currentRadius-=20) { // generate a random color CGFloat r = (float)rand() / RAND_MAX; CGFloat g = (float)rand() / RAND_MAX; CGFloat b = (float)rand() / RAND_MAX; UIColor *randColor = [[UIColor alloc] initWithRed:r green:g blue:b alpha:1.0]; // set the color [randColor setStroke]; CGContextAddArc(ctx, center.x, center.y, currentRadius, 0.0, M_PI * 2.0, YES); CGContextStrokePath(ctx); }


#7

I had a random function within the for loop that draws the circles.

[code] for (float currentRadius = maxRadius; currentRadius > 0; currentRadius -= 20) {
CGContextAddArc(ctx, center.x, center.y, currentRadius, 0.0, M_PI * 2.0, YES);

    // Perform drawing instruction; Removes path
    CGContextStrokePath(ctx);
    
    // Change to a new random color of 5 colors
    int colorInt = arc4random() % 5;
    
    switch (colorInt) {
        case 0:
            circleColer = [UIColor redColor];
            break;
        case 1:
            circleColer = [UIColor blueColor];
            break;
        case 2:
            circleColer = [UIColor greenColor];
            break;
        case 3:
            circleColer = [UIColor blackColor];
            break;
        case 4:
            circleColer = [UIColor purpleColor];
            break;
        case 5:
            circleColer = [UIColor orangeColor];
            break;
            
        default:
            break;
    }
    
    [[self circleColer] setStroke];
}[/code]

#8

We can use srand(unsigned int seed); to set the seed to be unique each time we launch the application:

srand((unsigned int)[[NSDate date] timeIntervalSince1970]);
for(float currentRadius = maxRadius ; currentRadius > 0 ;currentRadius -= 20)
{
//Set property circleColor to be a random color using RGBA
CGFloat r = rand()%101/100.0;
CGFloat g = rand()%101/100.0;
CGFloat b = rand()%101/100.0;
CGFloat a = (rand()%51 + 50)/100.0;
[self setCircleColor:[UIColor colorWithRed:r green:g blue:b alpha:a ]];

   //Set stroke color
    [[self circleColor] setStroke];
    //Set  path
    CGContextAddArc(ctx, center.x, center.y, currentRadius, 0.0, M_PI * 2.0, 1);
    //Perform  stroke drawing 
    CGContextStrokePath(ctx);
}

The view will look differently each time the application is launched.


#9

[quote=“spikeygoat”]Mine is probably the laziest solution. I took “Make the circles appear in assorted colors”, to mean "When you shake the device - make the circles appear in assorted colors. Which means I just updated the motionBegan:withEvent method in HypnosisView.m like so:

[code]- (void)motionBegan:(UIEventSubtype)motion withEvent:(UIEvent *)event {
if (motion == UIEventSubtypeMotionShake) {
NSArray *colourChoice = [[NSArray alloc] initWithObjects:
[UIColor blackColor],
[UIColor darkGrayColor],
[UIColor lightGrayColor],
[UIColor grayColor],
[UIColor redColor],
[UIColor greenColor],
[UIColor blueColor],
[UIColor cyanColor],
[UIColor yellowColor],
[UIColor magentaColor],
[UIColor orangeColor],
[UIColor purpleColor],
[UIColor brownColor],nil];

    self.circleColor = [colourChoice objectAtIndex:arc4random() % [colourChoice count]];
}

}[/code]

Then each time the device gets shaken the colors change.[/quote]

Thank you for this. I was trying to do exactly this before I even got to the challenge. I couldn’t figure it out though. I think I understand it better now.


#10

I did the same thing for my bronze solution… I like your style

[quote=“kenschenke”]I chose to generate a random color in each iteration of the for loop rather than selecting from a pre-filled list. It looks pretty trippy. Here’s my code:

for (float currentRadius=maxRadius; currentRadius>0; currentRadius-=20) { // generate a random color CGFloat r = (float)rand() / RAND_MAX; CGFloat g = (float)rand() / RAND_MAX; CGFloat b = (float)rand() / RAND_MAX; UIColor *randColor = [[UIColor alloc] initWithRed:r green:g blue:b alpha:1.0]; // set the color [randColor setStroke]; CGContextAddArc(ctx, center.x, center.y, currentRadius, 0.0, M_PI * 2.0, YES); CGContextStrokePath(ctx); } [/quote]


#11

I modified the drawRect: method to generate random colours for each of the circles.

I suppose it would have been better to break this out into its own method for generating a random colour to gain more control over colours at other times. This results in a multiple colours or nothing approach.

#define ARC4RANDOM_MAX 0x100000000

    // Draw concentric circles from the outside in
    for (float currentRadius = maxRadius; currentRadius > 0; currentRadius -= 20) {
        double redValue = floorf(((double)arc4random() / ARC4RANDOM_MAX) * 100.0f) / 100;
        NSLog(@"%f", redValue);
        double greenValue = floorf(((double)arc4random() / ARC4RANDOM_MAX) * 100.0f) / 100;
        NSLog(@"%f", greenValue);
        double blueValue = floorf(((double)arc4random() / ARC4RANDOM_MAX) * 100.0f) / 100;
        NSLog(@"%f", blueValue);
        
        [[UIColor colorWithRed:(CGFloat)redValue green:(CGFloat)greenValue blue:(CGFloat)blueValue alpha:1.0] setStroke];
        
        // Add a path to the context
        CGContextAddArc(ctx, center.x, center.y, currentRadius, 0.0, M_PI * 2.0, YES);
        
        // Perform drawing instructions; removes path
        CGContextStrokePath(ctx);
    }
    

#12

Here’s what I did. Very similar to a couple above.

[code]
//Set the stroke to the circleColor.
//[[self circleColor] setStroke];

//Draw concentric circles from the outside in.
for (float currentRadius = maxRadius; currentRadius > 0; currentRadius -= 20)
{
    
    //Just getting random values for R/G/B and alpha.
    //This will change the color randomly each time through the loop.

    //Get a random number from 0 to 10 for each variable.
    float r = rand() % 11;
    float g = rand() % 11;
    float b = rand() % 11;
    float alph = rand() % 11;
    
    //Divide the random 0 to 10 by 10 to get a decimal value.
    r = r/10;
    g = g/10;
    b = b/10;
    alph = alph/10;
    
    [self setCircleColor:[UIColor colorWithRed:r green:g blue:b alpha:alph]];

    //And don't forget to set the Stroke.
    [[self circleColor] setStroke];

    //Add a path to the context.
    CGContextAddArc(ctx, center.x, center.y, currentRadius, 0.0, M_PI * 2.0, YES);
    
    //Perform drawing instruction; removes path
    CGContextStrokePath(ctx);[/code]

}


#13

I have a similar solution the problem is, it keeps breaking and I’m not sure what I did wrong.The problem occurs at run time and I set a break on all exceptions, it seems to break on the line I commented below.

Basically I’ve set up to draw the circles with an array of colors and when it reaches the end to start at the first color. This would make it easy to design a pattern.

for (float currentRadius = maxRadius; currentRadius > 0; currentRadius -= 20) {
        
        
        //This block changes the colors and than repeats.
        int colorIndex;
                
        if (colorIndex == [colorArray count]) {
            //Go back to the first question
            colorIndex = 0;
        }
        [self setCircleColor:[colorArray objectAtIndex:colorIndex]]; //code breaks here
        colorIndex++;

        //set sets the circles color
        [[self circleColor]setStroke];
        
        //add a path to the context
        CGContextAddArc(ctx, center.x, center.y, currentRadius, 0.0, M_PI * 2.0, YES);
        
        //Perform drawing instruction; removes path
        CGContextStrokePath(ctx);

This is my init

-(id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    colorArray = [NSArray arrayWithObjects:[UIColor yellowColor],[UIColor purpleColor],[UIColor orangeColor],[UIColor greenColor],[UIColor redColor], nil];

    if (self) {
        //All Hynosisviews start with a clear background color
        [self setBackgroundColor:[UIColor clearColor]];
        [self setCircleColor:[UIColor greenColor]];

    }
    return self;
}

I also declared my array in the header file so that it would be globally accessible to my implementation file.

#import <Foundation/Foundation.h>

@interface HypnosisterView : UIView
{
    NSArray *colorArray;
}

@property (nonatomic, strong)UIColor *circleColor;

@end

#14

Here is my solution

First I declared an NSDictionary in HypnosisView.h

@interface HypnosisView : UIView { NSDictionary *colors; }

Then I populated the dictionary with:

colors = [NSDictionary dictionaryWithObjectsAndKeys: // VALUE KEY [UIColor darkGrayColor], [UIColor lightGrayColor], [UIColor blackColor], [UIColor darkGrayColor], [UIColor brownColor], [UIColor blackColor], [UIColor orangeColor], [UIColor brownColor], [UIColor redColor], [UIColor orangeColor], [UIColor magentaColor], [UIColor redColor], [UIColor purpleColor], [UIColor magentaColor], [UIColor blueColor], [UIColor purpleColor], [UIColor cyanColor], [UIColor blueColor], [UIColor greenColor], [UIColor cyanColor], [UIColor lightGrayColor], [UIColor greenColor], nil];

Then i put the color changing code in the //Draw concentric circles for loop in the drawRect method

[code]// Draw concentric circles from the outside in
for (float currentRadius = maxRadius; currentRadius > 0; currentRadius -=20)
{
[self setCircleColor:[colors objectForKey:circleColor]];
[[self circleColor] setStroke];

    // Add a path to the context
    CGContextAddArc(ctx, center.x, center.y, currentRadius, 0.0, M_PI * 2, YES);
    
    // Perform drawing instruction; removes path
    CGContextStrokePath(ctx);
}[/code]

So all in all this code creates circles with a pattern of different colors, and it was all done with only 4 additional lines to the original code.


#15

[quote=“kenschenke”]I chose to generate a random color in each iteration of the for loop rather than selecting from a pre-filled list. It looks pretty trippy. Here’s my code:
[/quote]

Yup, that’s pretty trippy! Cool, though - thanks for posting this.


#16

I went largely the same way the original poster did. As an interesting side effect, since I still had the “shake to change color” code still active, a new assortment of ring colors appeared each time I shook my device! :slight_smile:


#17

I did exactly what you guys did. However, only “[colors objectAtIndex:colorIndex] setStroke];” works at changing the colors, while “[self setCircleColor:[colors objectAtIndex:colorIndex]];” makes the circles retain their grey color. Any idea why?

(note that when I do shake my device, “[self setCirlceColor:[UIColor redColor]];” DOES work… weird.


#18

[quote=“dkindler”]I did exactly what you guys did. However, only “[colors objectAtIndex:colorIndex] setStroke];” works at changing the colors, while “[self setCircleColor:[colors objectAtIndex:colorIndex]];” makes the circles retain their grey color. Any idea why?

(note that when I do shake my device, “[self setCirlceColor:[UIColor redColor]];” DOES work… weird.[/quote]

The way I understand it, setStroke calls the setter for Stroke, which in turn defines the ‘nature’ of the ‘paint dots’ that the get painted along the path. setCircleColor just defines the nature of the circleColor variable - the robot (CGContext) that holds the instructions (strokepath) for how he’s going to swing his paintbrush (stroke) only cares about color of the paintbrush he’s holding - setCircleColor defines the color in the paintbucket but he has to be told to get the paint.

Maybe my analogy is bad, please let me know.


#19

Your analogy is good.

In more concrete terms, you could phrase it as follows.

changes the stroke color in the drawing context.

Where as

only changes the color in self itself.

Then in the drawing code, something like this must be done:

// set stroke color
[[self circleColor] setStroke]

to change the stroke color in the drawing context also.


#20

This is my solution to bronze

[code] // Draw concentric circles from the outside in
for(float currentRadius = maxRadius; currentRadius>0; currentRadius -= 20)
{
// Bronze Challenge
int randomNumber = rand() %3;
if (randomNumber == 0)
{
[[UIColor blackColor] setStroke];
}else if(randomNumber == 1)
{
[[UIColor greenColor] setStroke];

    }else if(randomNumber == 2)
    {
        [[UIColor blueColor] setStroke];
    }
    // end Bronze challenge
    
        
    // Add a path to a context
    CGContextAddArc(ctx, center.x, center.y, currentRadius, 0.0, M_PI*2.0, YES);
    
    // Perform drawing instruction; removes path
    CGContextStrokePath(ctx);
}[/code]