I have a random method to create 2 random integers. My concern is that %65-%70 of outputs are same integers like "5-5" "4-4" "3-3".
-(void)random{
NSUInteger randomNumber = arc4random_uniform(5);
switch (randomNumber) {
case 0:
_tile2.image = [UIImage imageNamed:#"one.png"];
break;
case 1:
_tile2.image = [UIImage imageNamed:#"two.png"];
break;
case 2:
_tile2.image = [UIImage imageNamed:#"three.png"];
break;
case 3:
_tile2.image = [UIImage imageNamed:#"four.png"];
break;
case 4:
_tile2.image = [UIImage imageNamed:#"five.png"];
break;
}
NSUInteger randomNumber2 = arc4random_uniform(5);
switch (randomNumber2) {
case 0:
_tile3.image = [UIImage imageNamed:#"one.png"];
break;
case 1:
_tile3.image = [UIImage imageNamed:#"two.png"];
break;
case 2:
_tile3.image = [UIImage imageNamed:#"three.png"];
break;
case 3:
_tile3.image = [UIImage imageNamed:#"four.png"];
break;
case 4:
_tile3.image = [UIImage imageNamed:#"five.png"];
break;
}
}
Should i create 25 different case to reach better result?
NSUInteger randomNumber = arc4random_uniform(25);
switch (randomNumber) {
case 0:
_tile2.image = [UIImage imageNamed:#"one.png"];
_tile3.image = [UIImage imageNamed:#"one.png"];
break;
case 1:
_tile2.image = [UIImage imageNamed:#"one.png"];
_tile3.image = [UIImage imageNamed:#"two.png"];
break;
case 2:
_tile2.image = [UIImage imageNamed:#"one.png"];
_tile3.image = [UIImage imageNamed:#"three.png"];
break;
case 3:
_tile2.image = [UIImage imageNamed:#"one.png"];
_tile3.image = [UIImage imageNamed:#"four.png"];
break;
case 4:
_tile2.image = [UIImage imageNamed:#"one.png"];
_tile3.image = [UIImage imageNamed:#"five.png"];
break;
case 5:
_tile2.image = [UIImage imageNamed:#"two.png"];
_tile3.image = [UIImage imageNamed:#"one.png"];
break;
...
}
}
arc4random_uniform is great for getting one random integer. When i need to get 2 or more random numbers, the outputs are not that great. What is the best way of doing this?
Sorry, but I don't believe you. You must be doing something other than what you've shown. The following code pasted into Playground consistently gives around a 20% match, not the 65-70% you claim:
import Cocoa
let sampleSize = 1000
var count = 0
for i in 1...sampleSize {
var randomNumber1 = arc4random_uniform(5)
var randomNumber2 = arc4random_uniform(5)
if randomNumber1 == randomNumber2 {
++count
}
}
println( Double(count) / Double(sampleSize) )
Whatever problem you're having, it isn't with how arc4random_uniform generates pairs of values.
Would using an array of numbers be a solution for you?
You can have a mutable array of numbers `[#0, #1, #2, #3, #4] and retrieve one number from a random index
NSMutableArray *array = [NSMutableArray arrayWithObjects:#0, #1, #2, #3, #4];
NSInteger firstIndex = arc4random_uniform([array count]);
NSNumber *firstNumber = array[index];
Remove the number you've just found:
[array removeObjectAtIndex:firstIndex];
And than repeat the same for the second number. The first retrieved number won't be in the array anymore so even if the arc4random_uniform() gives you the same value (your 65-70% case) the actual number you are gonna use in your switch case it's gonna be different.
This approach is probably a bit clumsy, but I think it does what you need giving you a bit of control over the randomness.
Related
In Swift it is possible to check a tuple like,
switch(type1, type2) {
case (1, 1):
functionNormal()
case (1, 2):
functionUncommon()
case (1, 3):
functionRare()
...
}
Is it possible to check tuple like multiple values in Objective-C Switch case? Any way around?
There could be various approaches, depending on exactly what your type1 and type2 data might be.
However, here is a basic example:
NSInteger i = 1;
NSInteger j = 2;
switch (i) {
case 1:
switch (j) {
case 1:
[self functionNormal];
break;
case 2:
[self functionUncommon];
break;
case 3:
[self functionRare];
break;
default:
NSLog(#"first value: 1 ... missing case for second value: for %ld", (long)j);
break;
}
break;
case 2:
switch (j) {
case 1:
[self secondFunctionNormal];
break;
case 2:
[self secondFunctionUncommon];
break;
case 3:
[self secondFunctionRare];
break;
default:
NSLog(#"first value: 2 ... missing case for second value: %ld", (long)j);
break;
}
break;
default:
NSLog(#"missing first case for first value: %ld", (long)i);
break;
}
This is rather inefficient, of course, but maybe it can get you on your way.
Edit
Again, it will depend on your data, but another approach more closely resembling your Swift example:
NSInteger i = 1;
NSInteger j = 2;
NSInteger ij = i * 1000 + j;
switch (ij) {
case 1001:
[self functionNormal];
break;
case 1002:
[self functionUncommon];
break;
case 1003:
[self functionRare];
break;
case 2001:
[self secondFunctionNormal];
break;
case 2002:
[self secondFunctionUncommon];
break;
case 2003:
[self secondFunctionRare];
break;
default:
NSLog(#"case was something else: %ld", (long)ij);
break;
}
i made a random for A-Z. The random letter is shown in a label. everything works fine. But the letter should not repeat till every letter from A-Z is called.
I´am new in xcode an need a litte help.
heres my code in the .m file.
NSString *letters = #"ABCDEFGHIJKLMNOPQRSTUVWXYZ";
-(NSString *) randomStringWithLength:(int) len {
NSMutableString *randomString = [NSMutableString stringWithCapacity: len];
for (int i=26; i<len; i++) {
[randomString appendFormat: #"%C", [letters characterAtIndex: arc4random() % [letters length]]]; buchstabeAusgabe.text = randomString;
}
return randomString;}
-(void)neuerGenerator {
int text = rand() %26;
switch (text) {
case 0:
buchstabeAusgabe.text =#"A";
break;
case 1:
buchstabeAusgabe.text =#"B";
break;
case 2:
buchstabeAusgabe.text =#"C";
break;
case 3:
buchstabeAusgabe.text =#"D";
break;
case 4:
buchstabeAusgabe.text =#"E";
break;
case 5:
buchstabeAusgabe.text =#"F";
break;
case 6:
buchstabeAusgabe.text =#"G";
break;
case 7:
buchstabeAusgabe.text =#"H";
break;
case 8:
buchstabeAusgabe.text =#"I";
break;
case 9:
buchstabeAusgabe.text =#"J";
break;
case 10:
buchstabeAusgabe.text =#"K";
break;
case 11:
buchstabeAusgabe.text =#"L";
break;
case 12:
buchstabeAusgabe.text =#"M";
break;
case 13:
buchstabeAusgabe.text =#"N";
break;
case 14:
buchstabeAusgabe.text =#"O";
break;
case 15:
buchstabeAusgabe.text =#"P";
break;
case 16:
buchstabeAusgabe.text =#"Q";
break;
case 17:
buchstabeAusgabe.text =#"R";
break;
case 18:
buchstabeAusgabe.text =#"S";
break;
case 19:
buchstabeAusgabe.text =#"T";
break;
case 20:
buchstabeAusgabe.text =#"U";
break;
case 21:
buchstabeAusgabe.text =#"V";
break;
case 22:
buchstabeAusgabe.text =#"W";
break;
case 23:
buchstabeAusgabe.text =#"X";
break;
case 24:
buchstabeAusgabe.text =#"Y";
break;
case 25:
buchstabeAusgabe.text =#"Z";
break;
default:
break;
}}
instead of the switch, perhaps store the alphabet in an NSMutableArray. When a letter is taken, remove it from the array. Instead of %26 do %[array count]. To look up the item in array, use [array objectAtIndex:index] where index is the random number.
I am not on XCode at the moment, but I'll try to write out the full code:
- (NSString *) randomStringWithLength:(int) len andAlphabet: (NSString *) alphabet {
NSMutableArray *alphabetArrayMut = [[self arrayFromString: alphabet] mutableCopy];
NSMutableString *resultString = [NSMutableString stringWithString:#""];
while([alphabetArrayMut count]&&[resultString length]<len){
int index = rand() % [alphabetArrayMut count];
NSString *charToAdd = [alphabetArrayMut objectAtIndex:index];
[resultString appendString:charToAdd];
[alphabetArrayMut removeObjectAtIndex:index];
}
return [resultString copy];
}
- (NSArray *) arrayFromString: (NSString *) string{
NSMutableArray *characters = [[NSMutableArray alloc] initWithCapacity:[string length]];
for (int i=0; i < [string length]; i++) {
NSString *ichar = [NSString stringWithFormat:#"%c", [string characterAtIndex:i]];
[characters addObject:ichar];
}
return [characters copy];
}
Note that it is probably a lot easier to use recursion. Unfortunately, I am not on my mac at the moment, so I can't test it:
- (NSString *) randomStringWithLength:(int) len andAlphabet: (NSString *) alphabet {
if(len <= 0 || ![alphabet count]){ // base case
return #"";
}
int index = rand() % [alphabet count];
NSString *chosenLetter = [alphabet substringWithRange:NSMakeRange(index, 1)];
NSString *newAlphabet = [alphabet stringByReplacingCharactersInRange:NSMakeRange(index, 1) withString:#""];
NSString *resultString = [NSString stringWithFormat:#"%#%#",chosenLetter,[self randomStringWithLength:len-1,newAlphabet];
return resultString;
}
Lots of different ways to do this. My suggestion would be to use a mutable array:
Add this statement to your .h file:
NSMutableArray *randomLetters;
And then add this method to your .m file:
(Code edited to clean up a ton of typos and minor mistakes)
- (NSString *) randomLetter;
{
if (randomLetters == nil)
randomLetters = [NSMutableArray arrayWithCapacity: 26];
if (randomLetters.count == 0)
{
for (unichar aChar = 'A'; aChar <= 'Z'; aChar++)
{
[randomLetters addObject: [NSString stringWithCharacters: &aChar length: 1]];
}
}
NSUInteger randomIndex = arc4random_uniform((u_int32_t)randomLetters.count);
NSString *result = randomLetters[randomIndex];
[randomLetters removeObjectAtIndex: randomIndex];
return result;
}
(Disclaimer: I typed that code out in the SO editor. I haven't tried to compile it, so it may contain minor typos.)
The method randomLetter will give you a single, non-repeating random letter every time you call it, until the array of remaining random letters is empty. At that point it will repopulate the array with the full alphabet and start over.
The random number generator arc4random_uniform() gives much better results that rand(), and doesn't suffer from "modulo bias" (link) like the expression rand()%range does.
Note that it is possible for the above method to give you the last random letter (an "a", for example") then on the next call, repopulate the array, and give you another "a" from the newly populated array. However, the odds of that happening are only 1 in 26.
You could tweak the above code so it remembers the last character it gives you and doesn't give you that same character twice in a row if that's important.
You could pretty easily change it slightly so that it would give you letters one at a time until it's empty and then return nil, and then write a separate method to fill it. That way you could get exactly 26 non-repeating characters and know when you about to repeat with another set of 26 characters.
because c string is terminal by '\0', we need 27 bytes.
NSString *alp = #"ABCDEFGHIJKLMNOPQRSTUVWXYZ";
char cstr[27];
[alp getCString:cstr maxLength:27 encoding:NSUTF8StringEncoding];
// do i from 25 to 0. to 1 is ok, also
for (int i = alp.length - 1; i >= 0; --i) {
int mark = arc4random_uniform(i);
char temp = cstr[i];
cstr[i] = cstr[mark];
cstr[mark] = temp;
}
NSString *str = [NSString stringWithUTF8String:cstr];
NSLog(#"%#", str);
Given these methods:
- (NSString *)stringOfRandomLettersWithLength:(NSUInteger)length {
if (length > 26) {
return nil;
}
NSMutableString *stringOfRandomLetters = [NSMutableString stringWithCapacity:length];
NSArray *letters = #[ #"A", #"B", #"C", #"D", #"E", #"F", #"G", #"H", #"I", #"J", #"K", #"L", #"M", #"N", #"O", #"P", #"Q", #"R", #"S", #"T", #"U", #"V", #"W", #"X", #"Y", #"Z" ];
NSMutableArray *unusedLetters = [letters mutableCopy];
NSString *randomLetter;
for (int i=0; i<length; i++) {
randomLetter = [self randomItemFromArray:unusedLetters];
[unusedLetters removeObject:randomLetter];
[stringOfRandomLetters appendString:randomLetter];
}
return stringOfRandomLetters;
}
- (NSString *)randomItemFromArray:(NSArray *)items {
if (items.count < 1) {
return nil;
}
return items[ arc4random_uniform((u_int32_t)items.count) ];
}
You could create a string of random, distinct letters like this:
NSString *label = [self stringOfRandomLettersWithLength:26];
NSLog(#"label= %#", label);
In the console you'd see something like this:
label= YGRHCXTFDZLKNPAIEOJSUQWVMB
I am using BradLarson's GPUImage library for filtering image.
I am using this code in my project.
GPUImagePicture *staticPicture;
Applying of filters are like this -
-(void) setFilter:(int) index {
switch (index) {
case 1:{
filter = [[GPUImageContrastFilter alloc] init];
[(GPUImageContrastFilter *) filter setContrast:1.75];
} break;
case 2: {
filter = [[GPUImageToneCurveFilter alloc] initWithACV:#"crossprocess"];
} break;
case 3: {
filter = [[GPUImageToneCurveFilter alloc] initWithACV:#"02"];
} break;
case 4: {
filter = [[GrayscaleContrastFilter alloc] init];
} break;
case 5: {
filter = [[GPUImageToneCurveFilter alloc] initWithACV:#"17"];
} break;
case 6: {
filter = [[GPUImageToneCurveFilter alloc] initWithACV:#"aqua"];
} break;
case 7: {
filter = [[GPUImageToneCurveFilter alloc] initWithACV:#"yellow-red"];
} break;
case 8: {
filter = [[GPUImageToneCurveFilter alloc] initWithACV:#"06"];
} break;
case 9: {
filter = [[GPUImageToneCurveFilter alloc] initWithACV:#"purple-green"];
} break;
default:
filter = [[GPUImageFilter alloc] init];
break;
}
Now I want to increase the brighness of the GPUImage without changing the current applied filter.How to do this ?
Include the below methods
-(UIImage*)applyFilterForImage:(UIImage*)img value:(NSNumber*)filterValue
{
switch (type) {
case kPhotoBrightness:
self.filterImage = [self applyBrightnessForImage:img value:filterValue];
break;
case kPhotoContrast:
self.filterImage = [self applyContrastForImage:img value:filterValue];
break;
case kPhotoSaturation:
self.filterImage = [self applySaturationForimage:img value:filterValue];
break;
case kPhotoHue:
self.filterImage = [self applyHueForImage:img value:filterValue];
break;
case kPhotoSharpness:
self.filterImage = [self applySharpnessForImage:img value:filterValue];
break;
default:
break;
}
return self.filterImage;
}
-(UIImage*)applyBrightnessForImage:(UIImage*)img value:(NSNumber*)filterValue {
GPUImageBrightnessFilter *brightnessFilter = (GPUImageBrightnessFilter*)self.filter;
[brightnessFilter setBrightness:[filterValue floatValue]];
return [self outputImageForFilter:brightnessFilter andImage:img];
}
//output the filtered image
-(UIImage*)outputImageForFilter:(GPUImageOutput<GPUImageInput>*)_filter andImage:(UIImage*)_image {
GPUImagePicture *filteredImage = [[GPUImagePicture alloc]initWithImage:_image];
[filteredImage addTarget:_filter];
[filteredImage processImage];
return [_filter imageFromCurrentlyProcessedOutputWithOrientation:_image.imageOrientation];
}
I created a simple calculator. Everything works great; however, if I divide by zero, I would like to show an error message. I know how to do alert popups, but I don't know how to implement it so it comes up when I divide by zero. Here is a snipped of my calculator code:
- (IBAction)buttonOperationPressed:(id)sender {
if (currentOperation == 0) result = currentNumber;
else {
switch (currentOperation) {
case 1:
result = result + currentNumber;
break;
case 2:
result = result - currentNumber;
break;
case 3:
result = result * currentNumber;
break;
case 4:
result = result / currentNumber;
break;
case 5:
currentOperation = 0;
break;
default:
break;
}
}
currentNumber = 0;
CalcDisplay.text = [NSString stringWithFormat:#"%g",result];
if ([sender tag] == 0) result = 0;
currentOperation = [sender tag];
userInTheMiddleOfEnteringDecimal = NO;
You can just add a test prior to doing the division e.g. change:
case 4:
result = result / currentNumber;
break;
to:
case 4:
if (currentNumber == 0)
// ... do alert here ...
else
result = result / currentNumber;
break;
You have to check if the second division operand is zero, and if yes, then print an error message. Don't forget, that you can't just compare double or something with ==, you have to use presicion, like this:
case 4:
if(ABS(currentNumber) < 1e-12) // most probably its zero
// your message
return;
- (IBAction)buttonOperationPressed:(id)sender {
if (currentOperation == 0) result = currentNumber;
else {
switch (currentOperation) {
case 1:
result = result + currentNumber;
break;
case 2:
result = result - currentNumber;
break;
case 3:
result = result * currentNumber;
break;
case 4:
if(currentNumber == 0){
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Title" message:#"Message" delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil, nil];
[alert show];
}else{
result = result / currentNumber;
}
break;
case 5:
currentOperation = 0;
break;
default:
break;
}
}
currentNumber = 0;
CalcDisplay.text = [NSString stringWithFormat:#"%g",result];
if ([sender tag] == 0) result = 0;
currentOperation = [sender tag];
userInTheMiddleOfEnteringDecimal = NO;
Please try this code, I have copied an pasted the code you have given and added some necessary lines to it which i felt would solve your issue.
I know that I can do this:
switch (imageNumber) {
case 1: image1.image = [UIImage imageWithContentsOfFile:[[NSBundle mainBundle] pathForResource:#"imageName" ofType:#"jpg"]]; break;
case 2: image2.image = [UIImage imageWithContentsOfFile:[[NSBundle mainBundle] pathForResource:#"imageName" ofType:#"jpg"]]; break;
case 3: image3.image = [UIImage imageWithContentsOfFile:[[NSBundle mainBundle] pathForResource:#"imageName" ofType:#"jpg"]]; break;
case 4: image4.image = [UIImage imageWithContentsOfFile:[[NSBundle mainBundle] pathForResource:#"imageName" ofType:#"jpg"]]; break;
}
I want to be more efficient in my code, so I am wondering if there is a way to do it like this:
switch (imageNumber) {
case 1: //somehow set image1 as the imageView I want used
case 2: //somehow set image2 as the imageView I want used
case 3: //somehow set image3 as the imageView I want used
case 4: //somehow set image4 as the imageView I want used
}
imageWhicheverWasSet.image = [UIImage imageWithContentsOfFile:[[NSBundle mainBundle] pathForResource:#"imageName" ofType:#"jpg"]];
Thanks in advance for your help!
The second code snippet you pasted yourself is actually very close to a solution. You just need to set UIImageView *imageToChange; as instance variable and then do:
imageToChange.image = nil; // will clear the image on last selected image view
// if you don't need that, just remove that line and leave others
switch (imageNumber) {
case 1: imageToChange = image1; break;
case 2: imageToChange = image2; break;
case 3: imageToChange = image3; break;
case 4: imageToChange = image4; break;
}
imageToChange.image = [UIImage imageWithContentsOfFile:[[NSBundle mainBundle] pathForResource:#"imageName" ofType:#"jpg"]];
You could put the UIImageViews in an array, then use the index to select the correct one. Not sure this would be useful unless you had a lot more UIImageViews to deal with.
NSArray* imageViews = [NSArray arrayWithObjects: image1, image2, image3, image4, nil];
UIImageView* theImage = [imageViews objectAtIndex: imageNumber-1];
UIImage* theImage = [UIImage imageWithContentsOfFile:[[NSBundle mainBundle] pathForResource:#"imageName" ofType:#"jpg"]];
You'd want to validate the imageNumber to make sure it was within range.
How about --
UIImage* theImage = [UIImage imageWithContentsOfFile:[[NSBundle mainBundle] pathForResource:#"imageName" ofType:#"jpg"]];
switch ...
case 1:image1.image = theImage; break;
case 2:...
You could also do --
MyImageType* tempImageObj = nil;
switch ... {
case 1:tempImageObj = &image1; break; // Or just image1, if ".image" is a property, not a field
case 2:...
}
tempImageObj ->image = [UIImage imageWithContentsOfFile:[[NSBundle mainBundle] pathForResource:#"imageName" ofType:#"jpg"]]; // Or "." instead of "->" if property.
Another way could be to use an array
UIImageView *iv[] = {
image1,
image2,
image3,
image4,
};
if (imageNumber>=0 && imageNumber<4)
iv[imageNumber].image = [UIImage imageWithContentsOfFile:[[NSBundle mainBundle]
pathForResource:#"imageName"
ofType:#"jpg"]]