# Challenge: Colors - My Solution

#1

So I think I figured out a clever way to generate the random colors of the arcs, however I wanted to post it because I wanted to get others opinions. Also, I was looking to see if there was a better way of getting a random float between 0 and 1 inclusive.

If you do not want to know a valid solution (even if it isn’t the most elegant) please stop reading.

How I thought if this was taking the book’s advice and looking up the documentation of UIColor. I found an init method (among others)

``- (UIColor *)initWithRed:(CGFloat)red green:(CGFloat)green blue:(CGFloat)blue alpha:(CGFloat)alpha``

The documentation that the variables red, green, blue, and alpha should be a float between 0.0 and 1.0 inclusive. Values below 0.0 are treated as 0.0 and values above 1.0 are treated as 1.0.

Anyhow, I did a google search and I found a way of getting a random float between 0.0 and 1.0

At the top of HypnosisView.m I defined a constant

``#define ARC4RANDOM_MAX      0x100000000``

Then I moved the setStroke message into the for loop which actually draws the circles and added some code. Here’s my changed for loop:

``````for (float currentRadius = maxRadius; currentRadius > 0; currentRadius -= 20)
{
// New code starts here
double red = ((double)arc4random() / ARC4RANDOM_MAX);
double green = ((double)arc4random() / ARC4RANDOM_MAX);
double blue = ((double)arc4random() / ARC4RANDOM_MAX);
double alpha = ((double)arc4random() / ARC4RANDOM_MAX);

[[[UIColor alloc] initWithRed:red green:green blue:blue alpha:alpha] setStroke];

// End of new code
CGContextStrokePath(context);
}``````

It actually looks pretty cool (in my opinion). Please let me know if anybody else has an easier way of doing this (especially the random 0.0 - 1.0 part)

#2

I got on a very similar track and was happy to come here to check and find your answer. It’s exactly the same logic but with slight differences in the color variables type and in the method used to set the new color:

``````// Draw concentric circles from the outside in
{
CGContextStrokePath(context);

// New Code Here - Attribute a new random color to the UIColor object
CGFloat red = (float)random()/RAND_MAX;
CGFloat green = (float)random()/RAND_MAX;
CGFloat blue = (float)random()/RAND_MAX;
CGFloat alpha = 1;

[[UIColor colorWithRed:red green:green blue:blue alpha:alpha] setStroke];
}``````

The main difference that intrigues me is that you created a UIColor object with alloc and used the method initWithRed:green:blue:alpha while I used the method colorWithRed:green:blue:alpha.

I think they are equivalent ways of doing the same thing but honestly not sure. I wonder if someone could comment on that.

Thanks

#3

Hi,

alloc / initWithRed:green:blue:alpha is an instance method and if you alloc something then it is your responsibility to release it.

whereas the class method UIColor colorWithRed:green:blue:alpha is autoreleased for you.

The first example is leaking.

Gareth

#4

here mine using the hue color space

```float i =0; for (float currentRadius = maxRadius; currentRadius > 0; currentRadius -=20) { [[UIColor colorWithHue:i saturation:1.0 brightness:1.0 alpha:1.0] setStroke]; CGContextAddArc(context, center.x, center.y, currentRadius,0,2.0 * M_PI, YES); CGContextStrokePath(context); if(i > 1.0) i = 0.0; else i = i + 0.1; } ```

#5

Here’s my approach

I deleted the line that sets the stroke color using UIKit’s UIColor class, and placed an equivalent (I think) Core Graphics stroke color method inside the for loop with randomized color values.

``````// [[UIColor lightGrayColor] setStroke];   // delete this line

// Draw concentric circles from the outside in
{
CGContextSetRGBStrokeColor(context,  (float)random()/RAND_MAX,  (float)random()/RAND_MAX,  (float)random()/RAND_MAX,  1.0 );

CGContextStrokePath(context);
}``````

#6

Note that arc4random() generates cryptographic-quality random numbers.

More “true randomness” means slower, which means more battery drain. random() is probably better suited for this. Even the least-true-random rand() function may be sufficient; the random() man page says it’s about 2/3 the speed of rand().

#7

Just to toss in yet another possibility…

I’d always wondered how to go through colours in “rainbow order,” and this challenge provided the excuse to learn that. I found that this blog post explained it very clearly.

So with that in mind, picking up after where center is defined…

``````    CGContextSetLineWidth( context, 10 );

double frequency = 0.3;
double amplitude = 0.5;
double waveCenter = 0.5;
int iteration = -1;
float alpha = 0.8;

++iteration;
float red   = (float)( sin( frequency * iteration + 0.0 ) * amplitude + waveCenter );
float green = (float)( sin( frequency * iteration + 2.0 ) * amplitude + waveCenter );
float blue  = (float)( sin( frequency * iteration + 4.0 ) * amplitude + waveCenter );

CGContextSetRGBStrokeColor( context, red, green, blue, alpha );

CGContextStrokePath( context );
}``````

FWIW.

#8

Here’s the way I did a rainbow:

[code] CGContextSetLineWidth(context, 10);
// [[UIColor lightGrayColor] setStroke]; move inside for loop

``````// Draw concentric circles from outside in
CGFloat hue;

[[UIColor colorWithHue: hue saturation: 1.0 brightness: 1.0 alpha: 1.0] setStroke];

CGContextStrokePath(context);
}[/code]
``````

Hue is the “shade” of a color going round a color wheel. This method varies it from 1 to 0, one trip around the wheel, as the circles are drawn from edge to center of the window.
edit: subbed maxRadius for the denominator in the hue calculation

#9

Cool — thank you for sharing!

#10

Hello,

I did it in a different way (reusing chapter 1). I thought it may be interesting too :

In HypnosisView.h

``````@interface HypnosisView : UIView
{
int currentColorIndex;
NSMutableArray *colors;
}
@end``````

In HypnosisView.m

``````- (void)drawRect:(CGRect)rect
{
// Create an array and make the pointer points to it
colors = [[NSMutableArray alloc] init];

// Add colors to the array

...same code as in the book until

// Draw concentric circles from the outside in
{
// Step to the next color
currentColorIndex++;

// Am I past the last color?
if (currentColorIndex == [colors count]) {

NSLog(@"[colors count] = %d", [colors count]);
NSLog(@"currentColorIndex = %d", currentColorIndex);

// Go back to the first color
currentColorIndex = 0;
}

// Change color
[[colors objectAtIndex:currentColorIndex] setStroke];

// Draw the circle
currentRadius, 0.0, M_PI * 2.0, YES);
CGContextStrokePath(context);
}

...same code as in the book until the end
}

@end``````

Hope it may helps some of us

Bye

#11

I did a similar thing to irochas, using UIColor objects in an array

I like the elegance of the random solutions in this topic, but there’s something to be said for the control you get from the array method with sequential color use.

[code] // Set the stroke color to light gray
// [[UIColor lightGrayColor] setStroke];

``````// Make an array of color objects
NSArray *colorArray = [NSArray arrayWithObjects:[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];

// Draw concentric circles from the outside in
int i = 0;
{
[[colorArray objectAtIndex:i] setStroke];
++i;
if ([colorArray count] == i) i = 0;
CGContextStrokePath(context);
}
``````

[/code]

#12

I went with a simpler/easier method to do it in my opinion. Moving the color setting command inside of the for loop and then looking up in the documentation for a way to manually set the color via RGB.

``````for (float currentRadius = maxRadius; currentRadius > 0; currentRadius -= 20)
{
[[UIColor colorWithRed:((float)rand() / RAND_MAX) green:((float)rand() / RAND_MAX) blue:((float)rand() / RAND_MAX) alpha:1.0] setStroke];
CGContextStrokePath(context);
}``````

I had to typecast rand() as a float to make sure that I would get a number between 0.0 and 1.0 - I set my alpha locked to 1.0 to make sure the colors weren’t dimmed. Produced a pretty cool image!

#13

I’ve tried using the random generators (like random()) but every time I load up the application the colors of the rings are the same each time so no randomness here.

Why is that?

#14

It makes use of the value of currentRadius, which changes incrementally from 16.888184 to 576.888184.

``````    // Draw concentric circles from the outside in

[[UIColor colorWithWhite:(1 - (currentRadius / 1000)) alpha:1.0] setStroke];

CGContextStrokePath(context);
}``````

#15

Here’s my take. I create an NSArray and initialized it with the colors of the rainbow. Then I used modulo within the for loop to call set stroke, cycling through my array

``````    // Create rainbows and shit
NSArray *rainbowColors = [[NSArray alloc] initWithObjects:[UIColor redColor],
[UIColor orangeColor],
[UIColor yellowColor],
[UIColor greenColor],
[UIColor blueColor],
[UIColor purpleColor],
nil];

// Draw concentric circle from the outside in
{
CGContextStrokePath(context);
}``````

Thanks for the challenges. It is the part where I usually learn the most

#16

[quote=“bpedit”]
Hue is the “shade” of a color going round a color wheel. This method varies it from 1 to 0, one trip around the wheel, as the circles are drawn from edge to center of the window.
edit: subbed maxRadius for the denominator in the hue calculation[/quote]

Very cool. My solution was nearly identical to yours except I went for random colors in a slightly different way than the other folks here:

[code] srandom(time(NULL)); // Seed the random number generator

``````// Draw concentric circles from the outside in
{
float hue = random()/(float)RAND_MAX;
[[UIColor colorWithHue:hue saturation:1.0 brightness:1.0 alpha:1.0] setStroke];
CGContextStrokePath(context);
}
``````

[/code]

#17

I have tried to create a very simple solution (as I am too stupid to do the clever stuff you have all done!)

In HypnosisView.m
I added an array before drawing the circles…

``````    // new code 1
NSArray *colorChoice = [NSArray arrayWithObjects:[UIColor redColor],
[UIColor blueColor],
[UIColor greenColor],
[UIColor yellowColor],
[UIColor purpleColor],
[UIColor whiteColor],
nil];``````

Then a little bit of randomisation…

``````    // draw the circles
{
// new code 2
int colorIndex = rand() % (int)[colorChoice count];
[[colorChoice objectAtIndex:colorIndex] setStroke];

// draw
center.x,
center.y,