Randomizing Square colors [closed] - ios

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 8 years ago.
Improve this question
I have four squares on my screen and I want each of the squares to display a different image every time for each square. I have got it to work, but as the code repeats sometimes there is a delay. I'm not sure what I'm doing wrong.
Here is my main code
#import "HomeScreenViewController.h"
#interface HomeScreenViewController ()
#end
#implementation HomeScreenViewController
-(void)startRandomSquares
{
self.greenImage = [UIImage imageNamed:#"GreenSquare.png"];
self.redImage = [UIImage imageNamed:#"RedSquare"];
self.blueImage = [UIImage imageNamed:#"BlueSquare"];
self.purpleImage = [UIImage imageNamed:#"PurpleSquare"];
self.arrayOfColors = [NSMutableArray arrayWithObjects:self.greenImage,self.redImage, self.blueImage, self.purpleImage, nil];
}
-(IBAction)Button1:(id)sender
{
self.startLabel.hidden = YES;
}
-(IBAction)Button2:(id)sender
{
}
-(IBAction)Button3:(id)sender
{
}
-(IBAction)Button4:(id)sender
{
}
-(void)randomizeAllSquares
{
[self randomizedSquare1];
[self randomizedSquare2];
[self randomizedSquare3];
[self randomizedSquare4];
}
-(void)randomizedSquare1
{
[self startRandomSquares];
randomColor = arc4random() % [self.arrayOfColors count];
square1RandomNumber = randomColor;
// NSLog(#"Square 1 : %d", square1RandomNumber);
//NSLog(#"Square 1 colors : %#", self.arrayOfColors);
switch (square1RandomNumber) {
case 0:
self.square1.image = self.arrayOfColors[0];
break;
case 1:
self.square1.image = self.arrayOfColors[1];
break;
case 2:
self.square1.image = self.arrayOfColors[2];
break;
case 3:
self.square1.image = self.arrayOfColors[3];
break;
default:
break;
}
if (square1RandomNumber == square2RandomNumber ) {
[self randomizedSquare1];
NSLog(#"Square 1-2 MATCH!!!");
}
if (square1RandomNumber == square4RandomNumber) {
[self randomizedSquare1];
NSLog(#"Square 1-4 Match!!!");
}
}
-(void)randomizedSquare2
{
[self startRandomSquares];
randomColor = arc4random() % [self.arrayOfColors count];
square2RandomNumber = randomColor;
//NSLog(#"Square 2 : %d", square2RandomNumber);
//NSLog(#"Square 2 colors : %#", self.arrayOfColors);
switch (square2RandomNumber) {
case 0:
self.square2.image = self.arrayOfColors[0];
break;
case 1:
self.square2.image = self.arrayOfColors[1];
break;
case 2:
self.square2.image = self.arrayOfColors[2];
break;
case 3:
self.square2.image = self.arrayOfColors[3];
break;
default:
break;
}
if (square2RandomNumber == square1RandomNumber ) {
[self randomizedSquare2];
NSLog(#"Square 2-1 Match!!!");
}
if (square2RandomNumber == square4RandomNumber) {
[self randomizedSquare2];
NSLog(#"Square 2-4 Match!!!");
}
}
-(void)randomizedSquare3
{
[self startRandomSquares];
randomColor = arc4random() % [self.arrayOfColors count];
square3RandomNumber = randomColor;
//NSLog(#"Square 3 : %d", square3RandomNumber);
//NSLog(#"Square 3 colors : %#", self.arrayOfColors);
switch (square3RandomNumber) {
case 0:
self.square3.image = self.arrayOfColors[0];
break;
case 1:
self.square3.image = self.arrayOfColors[1];
break;
case 2:
self.square3.image = self.arrayOfColors[2];
break;
case 3:
self.square3.image = self.arrayOfColors[3];
break;
default:
break;
}
if (square3RandomNumber == square2RandomNumber ){
[self randomizedSquare3];
NSLog(#"Square 3 - 2 MATCH!!!");
}
if (square3RandomNumber == square1RandomNumber) {
[self randomizedSquare3];
NSLog(#"Square 3- 1 MATCH!!");
}
}
-(void)randomizedSquare4
{
[self startRandomSquares];
randomColor = arc4random() % [self.arrayOfColors count];
square4RandomNumber = randomColor;
//NSLog(#"Square 4 : %d", square4RandomNumber);
//NSLog(#"Square 4 colors : %#", self.arrayOfColors);
switch (square4RandomNumber) {
case 0:
self.square4.image = self.arrayOfColors[0];
break;
case 1:
self.square4.image = self.arrayOfColors[1];
break;
case 2:
self.square4.image = self.arrayOfColors[2];
break;
case 3:
self.square4.image = self.arrayOfColors[3];
break;
default:
break;
}
if (square4RandomNumber == square2RandomNumber ) {
[self randomizedSquare4];
NSLog(#"Square 4-2 MATCH!!");
}
if (square4RandomNumber == square1RandomNumber) {
[self randomizedSquare4];
NSLog(#"SQuare 4-1 MATCH!!");
}
if (square4RandomNumber == square3RandomNumber) {
[self randomizedSquare4];
NSLog(#"Square 4-3 Match");
}
}

Ouch, that's a lot of code duplication. In general if you find yourself writing a similar piece of code multiple times it's not just best practice to generalize it, but you'll likely end up with a better solution.
A simple shuffle function on your array along with a simple reassign would work, and will give a runtime of N (ie the loop will only go through the array once per call). What you have now will technically try to create the color for a square multiple times in the case that it finds a match which is the reason for your slowness. Square 4 has a 3/4 chance that it will get the same color as another square so it likely runs at least 3 times before stopping.
- (void)shuffleImages
{
//uses the Fisher-Yates shuffle algorithm
for (NSUInteger i = self.arrayOfColors.count - 1; i >= 1; i--)
{
int index = arc4random_uniform(i+1);
[self.arrayOfColors exchangeObjectAtIndex:index withObjectAtIndex:i];
}
}
- (void)updateImages
{
[self shuffleImages];
self.square1.image = self.arrayOfColors[0];
self.square2.image = self.arrayOfColors[1];
self.square3.image = self.arrayOfColors[2];
self.square4.image = self.arrayOfColors[3];
}
All you need to do when you want your colors to change is call the updateImages function.

The delay comes from the check at the end of each randomisation. There's a 75% chance the number generated is in one of the other 3 squares, so it will loop and loop until it generates the only number it can be.
A better solution would be to shuffle the array of images, and then assign each image to each view in order.
e.g. (pseudo-code)
shuffle array of images
view 1 = array[0]
view 2 = array[1]
...
view 4 = array[3]

Brandon is right about the insane amount of code duplication, and using the fischer-yates algorithm is definitely the right way to go, but it sounds like you also want this to repeat, so you should use an NSTimer.
#property (strong, nonatomic) NSTimer *randomizeColorTimer;
- (void)startRandomizing
{
_randomizeColorTimer = [NSTimer scheduledTimerWithTimeInterval:0.25
target:self
selector:#selector(shuffleImages)
userInfo:nil
repeats:YES];
}
- (void)stopRandomizing
{
[_randomizeColorTimer invalidate];
_randomizeColorTimer = nil;
}

Related

How to change image on button?

I have two bottom left (<) side button and right (>) button. I have to change the images from array with left and right button action?
Code :
- (IBAction)onClickRightLeft:(id)sender {
switch ([sender tag]) {
case 10:
indexValueL++;
if(indexValueL >= 3)
{
indexValueL = 2;
}
if(indexValueL < 0)
{
indexValueL=0;
}
[imgViewStory setImageWithURL:[NSURL URLWithString:[NSString stringWithFormat:#"%#",[[[[arrGlobal objectAtIndex:indexValueL] valueForKey:#"FeaturedStoryImage"]]]];
break;
case 20:
indexValueR++;
if(indexValueR >= 3)
{
indexValueR = 2;
}
if(indexValueR < 0)
{
indexValueR=0;
}
[imgViewStory setImageWithURL:[NSURL URLWithString:[NSString stringWithFormat:#"%#",[[[[arrGlobal objectAtIndex:indexValueR] valueForKey:#"FeaturedStoryImage"]]]];
break;
default:
break;
}
How do I manage an array index?
I think this should do.. (not tested)
- (IBAction)onClickRightLeft:(id)sender {
switch ([sender tag]) {
case 10: // considering right clicked
indexValue++;
break;
case 20: // considering left clicked
indexValue--;
break;
}
if(indexValue >= 3)
{
indexValue = 0;
}
if(indexValue < 0)
{
indexValue=2;
}
[imgViewStory setImageWithURL:[NSURL URLWithString:[NSString stringWithFormat:#"%#",[[[[arrGlobal objectAtIndex:indexValue] valueForKey:#"FeaturedStoryImage"]]]];
Also while showing image, you should consider it caching & asynch loading. Check this for more info

ios - Making a Calendar. Year view is really slow. Lots of subviews

I'm making a calendar and the year view in particular, and understandably, is quite slow when coming into view.
The year view is simply a UICollectionView, and each month is a custom UICollectionViewCell XIB. The month has a title UILabel, and 7 dayName UILabels, and 42 dayNumber UILabels.
That's a total of 50 UILabels per month X 12. Aieesh...
How do other iOS calendar apps handle showing so many subviews without degradation in performance? The performance hit is mainly when swiping this view to the next and previous years. As the view is sliding in, the collection view is propagating the cells, causing the slow-down. I could hold off on populating the cells until the scrolling has stopped, but I'd really like to not show a white view as it's scrolling into the window.
Edit* As requested - my cellForRow method:
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
NSIndexPath *indexPathPlusOne = [NSIndexPath indexPathForRow:indexPath.row + 1 inSection:indexPath.section];
EICalendarYearViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:#"EICalendarYearViewCell" forIndexPath:indexPath];
if (_datesLoaded == YES)
{
//Get First Day in Month
NSMutableArray *arrayForDatesInMonth = [_dictHoldingArrayForEachMonth objectForKey:[NSNumber numberWithLong:indexPathPlusOne.row]];
NSDate *firstDayInMonth = arrayForDatesInMonth[0];
NSDateComponents* comp = [[NSCalendar currentCalendar] components:(NSCalendarUnitWeekday) fromDate:firstDayInMonth];
//setting month label
switch (indexPathPlusOne.row) {
case 1:
cell.labelTitle.text = #"January";
break;
case 2:
cell.labelTitle.text = #"February";
break;
case 3:
cell.labelTitle.text = #"March";
break;
case 4:
cell.labelTitle.text = #"April";
break;
case 5:
cell.labelTitle.text = #"May";
break;
case 6:
cell.labelTitle.text = #"June";
break;
case 7:
cell.labelTitle.text = #"July";
break;
case 8:
cell.labelTitle.text = #"August";
break;
case 9:
cell.labelTitle.text = #"September";
break;
case 10:
cell.labelTitle.text = #"October";
break;
case 11:
cell.labelTitle.text = #"November";
break;
case 12:
cell.labelTitle.text = #"December";
break;
default:
break;
}
//setting number of days in previous month to show.
long previousMonthDays = 0;
if (comp.weekday == 7)
{
previousMonthDays = 0;
}
else
{
previousMonthDays = comp.weekday - 1;
}
for (int i = 0; i < cell.arrayOfDayLabels.count; i++)
{
UILabel *labelDay = cell.arrayOfDayLabels[i];
//previous Month days
if (i <= previousMonthDays)
{
labelDay.text = #" ";
labelDay.textColor = [UIColor colorWithWhite:0.8 alpha:1.000];
}
//Actual days in current month
if (i >= previousMonthDays && i < previousMonthDays + arrayForDatesInMonth.count)
{
NSDate *dateForDay = arrayForDatesInMonth[i - previousMonthDays];
NSDateComponents *compsForDay = [[NSCalendar currentCalendar] components:NSCalendarUnitDay fromDate:dateForDay];
labelDay.text = [NSString stringWithFormat:#"%ld", (long)compsForDay.day];
labelDay.textColor = [UIColor darkGrayColor];
}
else
{
labelDay.text = #" ";
labelDay.textColor = [UIColor colorWithWhite:0.8 alpha:1.000];
}
}
}
else
{
for (int i = 0; i < cell.arrayOfDayLabels.count; i++)
{
UILabel *labelDay = cell.arrayOfDayLabels[i];
labelDay.text = #" ";
}
}
cell.layer.shouldRasterize = YES;
[cell.layer setRasterizationScale:3.0f];
return cell;
}
For rmaddy, a screenshot of the methods causing majority of slow-down.

swiping right, the page control's current page changes but the dots don't

I created a tutorial by some consequential images and added a page control on it. In addition, I added a swipe gesture which responds by changing the picture. In the code below, a switch case is defined in order to decide which image and dot should be the next according to the direction of swiping (left/right).
- (IBAction)handleSwipe:(UISwipeGestureRecognizer *)sender
{
// NSLog(#"swiped");
NSArray *images;
if (self.selectedRow == 0) {
images = [[NSArray alloc] initWithObjects:#"w8.JPG",#"w7.JPG",#"w6.JPG",#"w5.JPG",#"w4.JPG",#"w3.JPG", #"w2.JPG", #"w1.JPG" ,#"w9.JPG", nil];
self.pageControl.hidden = NO;
[self.pageControl setNumberOfPages:9];
UISwipeGestureRecognizerDirection direction = [(UISwipeGestureRecognizer *) sender direction];
switch (direction) {
case UISwipeGestureRecognizerDirectionRight:
if (pageController == 0 || imageIndex == 8)
{
self.Oops = [[UIAlertView alloc] initWithTitle:#"Oops!" message:#"You cannot swipe to the left, there are not any previous steps." delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil, nil];
[self.Oops show];
}
else {
[self.pageControl setCurrentPage:pageController - 1];
pageController = pageController - 1;
}
imageIndex++;
break;
case UISwipeGestureRecognizerDirectionLeft:
if (pageController < 8 && pageController >= 0) {
[self.pageControl setCurrentPage:pageController];
pageController = pageController + 1;
}
else {
[self.pageControl setCurrentPage: pageController ];
pageController = 0;
}
imageIndex--;
break;
default:
break;
}
NSLog(#"pagecontroller is %li and imageIndex is %li " , pageController, imageIndex);
imageIndex = (imageIndex < 0) ? ([images count] - 1): imageIndex % [images count];
self.imageView.image = [UIImage imageNamed:[images objectAtIndex:imageIndex]];
}
As you see in the code, there is a NSLog; when I run the app, everything works properly but when I swipe to the right to see a previous image, Although NSLog shows that all indexes of dots and images change correctly and we see the previous image, the dots don't change. Swiping to the right again, the dots change but it's late because the order of the images and dots that must be classified becomes disordered for example the last image is shown with the first dot.
I'm sure that my algorithm is correct, because I checked it with that NSLog, and also everything works fine before swiping to the right.
Any ideas?
I have changed the code a bit:
switch (direction) {
case UISwipeGestureRecognizerDirectionRight:
if (pageController != 0 && imageIndex != 9) {
[self.pageControl setCurrentPage:(pageController - 1)];
pageController --;
imageIndex++;
}
break;
case UISwipeGestureRecognizerDirectionLeft:
if (pageController <= 8 && pageController >= 0) {
[self.pageControl setCurrentPage:pageController];
pageController = pageController + 1;
imageIndex--;
}
break;
default:
break;
}
Now the only problem is that the page control counts the current dot twice when I swipe to a different direction.
Your imageIndex++ and imageIndex-- lines are in the wrong place. (You presumably don't want to change image if pageController is already 0, for example). Move them to:
- (IBAction)handleSwipe:(UISwipeGestureRecognizer *)sender
{
// NSLog(#"swiped");
NSArray *images;
if (self.selectedRow == 0) {
images = [[NSArray alloc] initWithObjects:#"w8.JPG",#"w7.JPG",#"w6.JPG",#"w5.JPG",#"w4.JPG",#"w3.JPG", #"w2.JPG", #"w1.JPG" ,#"w9.JPG", nil];
self.pageControl.hidden = NO;
[self.pageControl setNumberOfPages:9];
UISwipeGestureRecognizerDirection direction = [(UISwipeGestureRecognizer *) sender direction];
switch (direction) {
case UISwipeGestureRecognizerDirectionRight:
if (pageController == 0 || imageIndex == 8)
{
self.Oops = [[UIAlertView alloc] initWithTitle:#"Oops!" message:#"You should turn over to the left." delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil, nil];
[self.Oops show];
}
else {
[self.pageControl setCurrentPage:pageController - 1];
pageController = pageController - 1;
imageIndex++;
}
break;
case UISwipeGestureRecognizerDirectionLeft:
if (pageController < 8 && pageController >= 0) {
[self.pageControl setCurrentPage:pageController];
pageController = pageController + 1;
imageIndex--;
}
else {
[self.pageControl setCurrentPage: pageController ];
pageController = 0;
}
break;
default:
break;
}
NSLog(#"pagecontroller is %li and imageIndex is %li " , pageController, imageIndex);
imageIndex = (imageIndex < 0) ? ([images count] - 1): imageIndex % [images count];
self.imageView.image = [UIImage imageNamed:[images objectAtIndex:imageIndex]];
}
In your amended code, I think you need to set the page control differently (to pageController+1) for swipe left:
switch (direction) {
case UISwipeGestureRecognizerDirectionRight:
if (pageController != 0 && imageIndex != 9) {
[self.pageControl setCurrentPage:(pageController - 1)];
pageController --;
imageIndex++;
}
break;
case UISwipeGestureRecognizerDirectionLeft:
if (pageController <= 8 && pageController >= 0) {
[self.pageControl setCurrentPage:pageController+1];
pageController = pageController + 1;
imageIndex--;
}
break;
default:
break;
}

Display array of Images in UIImageView

array of images added into Project
imaging is the UIImageView and imagg is Image choosen by user its default
_imaging.image=imagg;
arr = [NSArray arrayWithObjects:
[UIImage imageNamed:#"1.jpg"],
[UIImage imageNamed:#"2.jpeg"],
[UIImage imageNamed:#"3.jpeg"],
[UIImage imageNamed:#"4.jpeg"],
[UIImage imageNamed:#"5.jpeg"],
nil];
assume user selected third image i.e 3.jpeg i am showing the 3.jpeg in imageview. Then using two button actions respectively Next and Previous next or previous images 3.jpeg should display.
- (IBAction)previous:(id)sender {
////
}
- (IBAction)next:(id)sender {
//////
}
}
for the next action its starting from 2nd image even for previous action its starting from 1st image.
this is the simple concept, this is working in static method, but working fine
assign the one global variable
#property (strong,nonatomic) NSString *imagestr;
- (IBAction)previous:(id)sender {
int str=[imagestr integerValue];
NSLog(#"the int value==%d",str);
switch (str) {
case 0:
_imaging.image=[arr objectAtIndex:4];
imagestr=#"4";
break;
case 1:
_imaging.image=[arr objectAtIndex:0];
imagestr=#"0";
break;
case 2:
_imaging.image=[arr objectAtIndex:1];
imagestr=#"1";
break;
case 3:
_imaging.image=[arr objectAtIndex:2];
imagestr=#"2";
break;
case 4:
_imaging.image=[arr objectAtIndex:3];
imagestr=#"3";
break;
default:
break;
}
}
- (IBAction)next:(id)sender {
int str=[imagestr integerValue];
NSLog(#"the int value==%d",str);
switch (str) {
case 0:
_imaging.image=[arr objectAtIndex:1];
imagestr=#"1";
break;
case 1:
_imaging.image=[arr objectAtIndex:2];
imagestr=#"2";
break;
case 2:
_imaging.image=[arr objectAtIndex:3];
imagestr=#"3";
break;
case 3:
_imaging.image=[arr objectAtIndex:4];
imagestr=#"4";
break;
case 4:
_imaging.image=[arr objectAtIndex:0];
imagestr=#"0";
break;
default:
break;
}
}
On clicked on next button
Before using this first set currentIndex in this
-(IBAction)next{
if (arr.count > 0) {
currentIndex++;
if (currentIndex > arr.count - 1) {
currentIndex = 0;
}
imageViewObj.image = [arr objectAtIndex:currentIndex];
}
}
on pervious button
-(IBAction)pervious{
if (arr.count > 0) {
currentIndex--;
if (currentIndex <= 0) {
currentIndex = arr.count - 1;
}
imageViewObj.image = [arr objectAtIndex:currentIndex];
}
}
Try this is working fine
Set some integer property currentIndex to 2 (if you load first the 3rd image).
When calling the next/previous methods increment/decrement that property and load the correct image. ImageView *image = [arr objectAtIndex:currentIndex]
when you initialize your view controller, keep track of the current image being viewed for example 0, to be used as an array index.
When next is pressed, increment the index and retrieve the image from the array using the updated count.
e.g.
- (IBAction)next:(id)sender {
imageCount++;
[myImageView setImage:[UIImage imageNamed:arr[imageCount] ];
}
hope this helps. :)

4 random function in specific interval time

I have 4 function and i want to execute them randomly every 1 second for unlimited time.
This is my code to execute a random function:
-(void) Game
{
int rand = arc4random() % 5;
switch (rand) {
case 0:
[self appearred];
break;
case 1:
[self appearblue];
break;
case 2:
[self appearyellow];
break;
case 3:
[self appeargreen];
break;
}
}
But how can i repeat this function every 1 second??
You can also try like this
*
-(void) Game
{
int rand = (int)arc4random() % 4;
switch (rand) {
case 0:
[self appearred];
break;
case 1:
[self appearblue];
break;
case 2:
[self appearyellow];
break;
case 3:
[self appeargreen];
break;
}
[self performSelector:#selector(Game) withObject:nil afterDelay:1.0];
}
*
It will call the Game Functions after each second
Just use a NSTimer.
PS : You will not be 100% sure that this will append every 1second.
Use below code which will call Game method every 1.0 second. One more thing, in your Game method you need to use % 4 instead of % 5 to get value between 0 to 3.
[NSTimer scheduledTimerWithTimeInterval:1.0
target:self
selector:#selector(Game)
userInfo:nil
repeats:YES];
-(void) Game
{
int rand = (int)arc4random() % 4;
switch (rand) {
case 0:
[self appearred];
break;
case 1:
[self appearblue];
break;
case 2:
[self appearyellow];
break;
case 3:
[self appeargreen];
break;
}
}

Resources