Randomizing object values without duplication - ios

I'm creating a game with SpriteKit. I have 8 different colored balls positioned at 8 different designated CGPoints on the screen. Once the user gets to a certain score, I would like to randomize the colors of the balls to all be different colors, but I would like to get this result without any of the colors and types duplicating.
I added the balls as objects to a global NSMutableArray and set up a method to enumerate the array. I then wrote an arc4random method to pick a random color type from the array and then apply it to the old ball type. Unfortunately I am getting some duplicates. Does anybody have any suggestions to help me randomize my ball types without duplication?
FYI, I have taken ample time out to read other randomization methods and none of them seem to necessarily answer my question. I am on a deadline. Can somebody please help me?
-(void)ballRotation{
NSLog(#"initial ball list: %#",_ballList);
[_ballList enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
int selectedIndex = arc4random() % _ballList.count;
NSLog(#"Selected Index: %i", selectedIndex);
//get a remain list of temp
Ball *newBall = _ballList[idx];
//get the ball at the current _ballList index
Ball *oldBall = _ballList[selectedIndex];
//change the ball in the old position to have the type & texture of the randomly selected ball
oldBall.Type = newBall.Type;
oldBall.texture = newBall.texture;
NSLog(#"new ball list: %lu", newBall.Type);
NSLog(#"new ball list: %#", newBall.texture);
[_ballList removeObjectAtIndex:selectedIndex];
}];
}

Create the array with all the colors. Shuffle it and assign to each ball in order. See Fisher-Yates Shuffle. Here's a category to do it:
#import <Foundation/Foundation.h>
#interface NSMutableArray (KD)
-(void) kd_shuffleArray;
#end
#implementation NSMutableArray (KD)
-(void) kd_shuffleArray {
NSUInteger count = self.count;
for (int i=count-1; i>0; i--) {
int random = arc4random_uniform(i+1);
[self exchangeObjectAtIndex:i withObjectAtIndex:random];
}
}
#end
Oh, and you never want to add/remove to an array while enumerating. It's one of the deadly sins.

Create a mutable array that stores the colors that get selected. Each time you randomize and get a color, compare that color to all the colors stored in the "alreadyChosenColor" array. If the colors are equal, randomize again until it finally does not match a color already existing in the array.
Code:
//Create an array named allColorArray with all colors in it that you will use
bool unique = NO;
while(unique==NO)
{
unique = YES;
//randomIndex is a random int in the range of the allColorArray
randomColor = [allColorArray objectAtIndex:randomIndex]
for(int i=0;i<alreadyChosenColor.count;i++)
{
if([alreadyChosenColor objectAtIndex:i]== randomColor)
unique=false;
}
}
//Set SKSpritenode to use randomColor.
//add randomColor to alreadyChosenColor array.

Related

How to compare various NSArrays in Objective-c?

My code contains four NSArrays, each of which contains two objects which represent XY-Coordinate at any point on the screen. Two or more arrays may contain same set of coordinates. I need to find the coordinate which has highest number of repetition among these four arrays. Can the isEqualTo: method help in this case?
One approach would be to maintain an NSDictionary, use the coordinates in your arrays as keys and then maintain a counter for each coordinate (i.e. key) that you increment whenever you see the same coordinate.
This could look somewhat like this:
NSMutableDictionary *coordinateCount = [[NSMutableDictionary alloc] init];
for (int i = 0; i < coordinates.length; i++) { // do this loop for each of your 4 arrays
Coordinate *c = coordinates[i];
if ([coordinateCount containsKey:c]) {
NSInteger count = [coordinateCount[c] integerValue];
count++;
coordinateCount[c] = #(count);
}
else {
coordinateCount[c] = #(1);
}
}
// now you can retrieve the max count value from all collected values
Note that this code is not tested and has to be adjusted depending on your types and variable names.

iPhone - how to select from a collection of UILabels?

I have a few UILabels, any one of which will update according to the index of an NSArray index they represent. I thought of selecting them by their tag
self.displayLabel.tag = myArray[index];
but that changes the tag value to whatever my array is holding at the moment
Using a dictionary for whatever tricks it offers instead of an NSArray doesn't help because i still have to select the correct matching label. This is the effect i want to achieve.
self.|mySelectedLabel|.text = myArray[index];
what should i put in |mySelectedLabel| to get the one i'm looking for?
I'm almost ashamed to ask at my reputation level, but this is stymie-ing me
every search only turns up how to set Labels and change, not the process of selecting
Assuming you have set the tags to the appropriate index to match your
array indices you can use [self.view viewWithTag:index];
Why are you not setting the tag with:
self.displayLabel.tag = index;
Also, you could just loop though an array of labels and find the right one:
for (UILabel *label : labelArray) {
if (label.tag == index) {
label.text = #"I found you!";
}
}
Rather than using tags you can refer to your specific textfields by reference:
// Create an array to hold your textfields
NSMutableArray *textFields = [NSMutableArray array]
// Create your textfields and add them to the array
UITextField *textField;
for (NSUInteger idx = 0: idx++; idx < numberOfTextFieldsYouWant) {
textField = [UITextField alloc] initWithFrame:<whateverYouWant>];
[textFields addObject:textField];
}
Since you are adding the objects to an array, rather than using the tag value 0, 1, 2... you can just access it by it's index in the array
So, for what you want to do you can just do:
textfields[index].text = myArray[index];
It's a lot cleaner, doesn't rely on magic tags, and you have an array of all your dynamic textfields that you can remove, or change in one place.
I think tags are vastly overused, and they aren't necessary in most cases.
Just letting you know I reframed the problem and this eventually worked for me without having to use an array
( with endless experimenting, I sort of bumped into it so I don't know if it constitutes good technique )
the desired label corresponding to the bag weight ( one of a number possible ) displays the right update
- (IBAction)acceptWeight:(UIButton *)sender {
int tempValue = (int) currentWeight;
// current weight comes from a UISegementedController
for (UILabel *labels in self.view.subviews)
{
if (labels.tag == currentWeight)
{
bags[tempValue]++;
labels.text = [NSString stringWithFormat:#"%i",bags[tempValue]];
}
}
totalKilo = totalKilo + (int)currentWeight;
self.totalKilo.text = [NSString stringWithFormat:#"%d",totalKilo];
}

uitableview ios: sorting array based on calculated distance not part of the array

I have an array of points on a map.
I populate the array correctly and I make annotations for them on the map. everything is working fine.
I have another tableview with the same array, and in the "subtitle" of the cells, I calculate the distance to user and present. everything working fine.
Now,I want to sort the list in the table view, in other words I want to sort the same array by distance, lowest to highest.
The thing is that the distance is not part of the array. so how can I cross match the distance with the array, so that when I sort the distance, it takes its belonging object in the array with it and sorts the array as well?
I am fairly new to ios but I have managed to release 3 apps now, and this one is the fourth, far more complex and I think I have covered pretty good ground with making the app so far. From the mapview, to the tableview with a search controller and everything. I am only missing the sorting.
I imagine I need to add some tag or property to each object in the array and assign it to each distance in the distance array.
Any suggestions would be appreciated :)
Thanks in advance.
// Assuming you have your points on the map in an NSArray called
// pointsOnMapArray and your distances in distanceArray, create a
// new mutable array to hold both. Note, the "distances" in this
// case are stored as NSStrings. We'll want to convert them to
// doubles before sorting them.
NSMutableArray *newArray = [[NSMutableArray alloc] init];
// Iterate over all of the points, and add a new element to the mutable
// array which is a new array containing a point and its distance. The
// distance is converted from an NSString to an NSNumber containing a
// doubleValue.
int i;
for (i = 0; i < pointsOnMapArray.count; i++) {
NSArray *newItem = [NSArray arrayWithObjects: [pointsOnMapArray objectAtIndex: i], [NSNumber numberWithDouble:[[distanceArray objectAtIndex: i] doubleValue]], nil];
[newArray addObject: newItem];
}
// Now, sort the new array based upon the distance in the second element
// of each array (ie, the distance).
[newArray sortUsingComparator: ^(id obj1, id obj2) {
NSNumber *dist1 = [obj1 objectAtIndex:1];
NSNumber *dist2 = [obj2 objectAtIndex:1];
return [dist1 compare:dist2];
}];
try making a dictionary with distances and elements of array . then by sorting the distances , array elements can be sorted accordingly.
NSMutableDictionary *dict=[[NSMutableDictionary alloc]init];
[dict setObject:(array element) forKey:(correspondingDistance)];
Now by sorting the keys , you can sort the elements of your array accordingly.

How to set instance variables from an NSMutableArray?

So I'm at the point where I'm starting to reduce my spaghetti code down.
So right now, I have 11 different dinosaur images that I've put into an NSMutableArray using a "for" loop. I've also declared CCSprite instance variables in which I was hoping I can set each dinosaur image to so that I can check bounding boxes, set positions, etc. So I pointed each object from the array to an instance variable So far, I have this code:
.h file:
CCSprite *dinosaur1_c;
CCSprite *dinosaur2_c;
CCSprite *dinosaur3_c;
CCSprite *dinosaur4_c;
CCSprite *dinosaur5_c;
CCSprite *dinosaur6_c;
CCSprite *dinosaur7_c;
CCSprite *dinosaur8_c;
CCSprite *dinosaur9_c;
CCSprite *dinosaur10_c;
CCSprite *dinosaur11_c;
.m file
NSMutableArray *dinoSprites = [[NSMutableArray alloc] init];
for( int i = 1, j = 0; i <= 11 && j <= 10; i++, j++ )
{
id dino = [CCSprite spriteWithSpriteFrameName:[NSString stringWithFormat:#"dinosaur%d-c.png", i]];
[dinoSprites addObject:dino];
[sceneSpriteBatchNode addChild:dino];
}
dinosaur1_c = (CCSprite *)[dinoSprites objectAtIndex:0];
dinosaur2_c = (CCSprite *)[dinoSprites objectAtIndex:1];
dinosaur3_c = (CCSprite *)[dinoSprites objectAtIndex:2];
dinosaur4_c = (CCSprite *)[dinoSprites objectAtIndex:3];
dinosaur5_c = (CCSprite *)[dinoSprites objectAtIndex:4];
dinosaur6_c = (CCSprite *)[dinoSprites objectAtIndex:5];
dinosaur7_c = (CCSprite *)[dinoSprites objectAtIndex:6];
dinosaur8_c = (CCSprite *)[dinoSprites objectAtIndex:7];
dinosaur9_c = (CCSprite *)[dinoSprites objectAtIndex:8];
dinosaur10_c = (CCSprite *)[dinoSprites objectAtIndex:9];
dinosaur11_c = (CCSprite *)[dinoSprites objectAtIndex:10];
This bit of code does work, but I'm sure it can be reduced. How would I be able to set each of these instance variables using the "for" loop?
I'm using these instance variables in other methods to set positions, check collisions/intersects, fade ins, etc.
I put an equivalent-code to better explain what I'm trying to do:
NSMutableArray *dinoSprites = [[NSMutableArray alloc] init];
for( int i = 1, j = 0; i <= 11 && j <= 10; i++, j++ )
{
id dino = [CCSprite spriteWithSpriteFrameName:[NSString stringWithFormat:#"dinosaur%d-c.png", i]];
[dinoSprites addObject:dino];
[sceneSpriteBatchNode addChild:dino];
// Set instance variables
dinosaur%i_c = (CCSprite *)[dinoSprites objectAtIndex:j];
}
Is there a way to achieve what I am asking? After 2.5 hours of searching, I still have come up with nothing. Just finding solutions for animation frames.
Am I missing something small or should I have a different way to point to each image in the array to set their positions, fade ins, check bounding boxes, etc?
Any ideas / inputs are greatly appreciated!! Thanks for taking the time to read this! :D
Instead of having eleven CCSprite instance variables, you should just have one NSArray.
So in your .h:
#property (strong) NSArray *dinoSprites;
In your .m, do a
#synthesize dinoSprites;
and then replace the code from your question with:
NSMutableArray *newDinoSprites = [[NSMutableArray alloc] init];
for( int i = 1, j = 0; i <= 11 && j <= 10; i++, j++ )
{
id dino = [CCSprite spriteWithSpriteFrameName:[NSString stringWithFormat:#"dinosaur%d-c.png", i]];
[newDinoSprites addObject:dino];
[sceneSpriteBatchNode addChild:dino];
}
self.dinoSprites = [newDinoSprites copy];
And then, whenever you need to refer to what you used to call, say, dinosaur8_c you would instead just use (CCSprite *)[dinoSprites objectAtIndex:7].
Is there a way to achieve what I am asking? After 2.5 hours of
searching, I still have come up with nothing. Just finding solutions
for animation frames.
You seem to want a variable whose value is another variable, so that you can iterate over a set of ivars. I can think of two ways to do something like what you're asking.
The first way is to use the address of each variable, i.e. a pointer to each variable. Since pointers themselves are scalar values, not objects, you'd need to use a C-style array:
CCSprite *ivars[] = {&dinosaur1_c, &dinosaur2_c, &dinosaur3_c, &dinosaur4_c};
for (int i = 0; i < 4; i++) {
*(ivars[i]) = [dinoSprites objectAtIndex:i];
}
The second way is to use key value coding. Construct the name of each ivar as a string, and then use that as the key in a call to -setValue:forKey: like this:
NSString *name;
for (int i = 0; i < [dinoSprites count]; i++) {
name = [NSString stringWithFormat:#"dinosaur%d_c", i];
[self setValue:[dinoSprites objectAtIndex:i] forKey:name];
}
All that said, I'd strongly encourage you to not take either of the preceding two approaches to your problem. It's very likely that there are much better solutions to your problem that don't involve having a separate ivar for each dinosaur. You've already got the dinosaurs in an array, so there's no need to create a separate ivar for each. As a general rule, if you ever find yourself creating numbered variables like this, you should probably step back and rethink what you're doing -- numbering your variables is a strong signal that you should be using an array instead.
So, in your case, I don't see any reason that you couldn't use the array you already have everywhere in your code. Instead of dinosaur6_c, you can obviously use [dinoSprites objectAtIndex:6]. But you'll really clean up your code if you think of ways to treat all the dinosaurs with the same code, so that you're never hard-coding specific indicies into your array. For example, if you need to set each dinosaur to a different position, there are at least two good ways to go about it. One is to compute the position, if possible, based on the index. You can do this if you're laying out the dinosaurs in a regular way, like on a 3 x n grid:
for (int i = 0; i < [dinoSprites count]; i++) {
int row = i / DINOS_PER_ROW;
int column = i % DINOS_PER_ROW;
CGPoint position = CGPointMake(row * rowHeight, column * columnWidth);
[[dinoSprites objectAtIndex:i] setPosition:position];
}
If the position of each dinosaur isn't computable from its index in the array, then you're probably currently hard-coding the positions in your code. You can clean that up by at least moving the positions to an array, and perhaps by reading that array in from a data file. That will make your code much shorter, easier to understand, and easier to maintain:
NSArray *positions = [NSArray arrayWithContentsOfURL:someURL]; // read positions from a property list
NSAssert([positions count] >= [dinoSprites count], #"Not enough positions!");
for (int i = 0; i < [dinoSprites count]; i++) {
CGPoint position = [[positions objectAtIndex:i] pointValue];
[[dinoSprites objectAtIndex:i] setPosition: position;
}
Of course, I'm just using the position of the sprite here as an example. You can do exactly the same thing with any attribute that you'd want to apply to a dinosaur, and you can even do them all at once. Instead of a positions array that you load from a property list, you could load an array of dictionaries, where each dictionary contains a number of attributes (color, favorite food, speed, hunger level, etc.).

hittin UIImageViews with another UIImageView

I have 10 UIImageViews on the screen. They are all in an array called posArray. I also have another UIImageView that is dragged by user and can hit those other 10. What is the easies way of displaying a simple NSlog message if the one object hits any of the other 10?
Right now i'm using touchesBegin, touchesMoved to move my one object and this array below to test if the one objects hits any of the other ten.
I'm just thinking that there is an easier, less memory spending way, way of doing this for some reason.
for (int i = 0; i < [posArray count]; i++) {
UIImageView *tempPos;
tempPos = [posArray objectAtIndex:i];
if (CGRectIntersectsRect(red1.frame, tempPos.frame)) {
red1.center = CGPointMake(tempPos.center.x, tempPos.center.y);
NSLog(#"position piece touched");
}
}
You can also use fast enumeration to get some more speed. Also you can add a break statement after you found one match (if you just need one match):
for (UIImageView * tempPos in posArray){
if (CGRectIntersectsRect(red1.frame, tempPos.frame)) {
red1.center = CGPointMake(tempPos.center.x, tempPos.center.y);
NSLog(#"position piece touched");
break;
}
}

Resources