Monday, September 19, 2011

Introducing quiz level logic

Ok, so now that we have the quiz level restoring from prefs, we'll return to take care of what happens when you get to the end of a quiz level. What we want to do when we get to the end of a quiz is to show a "Congratulations" screen and increase the quiz numbers by the difference between the previous start and end quiz numbers.

Let's take a look at what the Android app. does in this case.

It's doing this:

if (appState.quizSequenceIndex < appState.quizSequence.size()) {


So, I guess the quizSequenceIndex is actually the same thing that I'm now calling "shuffledArrayIndex", and the shuffledQuestionDictKeyList the same as the quizSequence. Funny how these names get changed around.

Ok, so, I guess I want to do something like this:


- (void) advance_question: (BOOL) animated {

if (appState.shuffledArrayIndex < [appState.shuffledQuestionDictKeyList count])
{

currentQuestion = [appState currentQuestion];

answers = [currentQuestion getAnswerArray: appState];

int rand = arc4random() % 3; // get a number between 0 and 3

NSLog(@"rand: %d", rand);
NSLog(@"Current Question kanji: %@", [currentQuestion questionKanji]);
NSLog(@"Current Question hiragana: %@", [currentQuestion hiragana]);

appState.slotOfCorrectAnswer = rand;

[answers removeObjectAtIndex: rand];
[answers insertObject:[currentQuestion hiragana] atIndex:rand];


// triggers reload, see veiwDidLoad method
[tableView reloadData];

}
else
{
NSLog(@"QuestionController - moving to next level");
}

}



And we got it:

2011-09-19 17:55:34.583 JlptQuizApp[1161:207] QuestionController - moving to next level


Ok, now what did the Android app do?


} else { // finished

// Do this to keep highlight in reversed position from showing up
makeListTranparent(this.getListView());

int pct = CalcTotals.calcPctCorrect((AppState) this
.getApplicationContext());

if (pct < 100) {

text = "You correctly answered " + appState.correctAnswers
+ " out of " + appState.quizSequence.size()
+ " for a total score of " + pct + "%";

Toast.makeText(getApplicationContext(), text, Toast.LENGTH_LONG)
.show();

} else {

// pass control to next level activity
Intent intent = new Intent(QuestionActivity.this,
NextLevelActivity.class);

startActivity(intent);
}

finish();
}


Ok - so, if they got any wrong, it would display a message, although it's not clear exactly how it restarts - right now it tries to advance the question and crashes. Otherwise, it does the beautiful display of the "Congratulations", which includes original artwork.

So, let's figure out how it doesn't increment out of the array on the Android. Ah, ok, it's the "finish", which takes it back to the start controller, which in turn resets it. So, what's our version of this?

Ok, I got it. The way we were returning to the previous display in our previous app was this:


-(IBAction)popViewController:(id)sender {

// return to previous screen
[self.navigationController popViewControllerAnimated:YES];
}


which was connected to the "next question" button. But in this case, we're going to do it if there was a wrong answer. Let's try it:

else
{
NSLog(@"QuestionController - moving to next level");
[self.navigationController popViewControllerAnimated:YES];

}


Yes, nice, it goes back to the start view. But, hold, not so fast now. When I click to go back to the questions, I get a "bad access" error on the statement before the release.

- (IBAction)openQuestionController
{
NSLog(@"openQuestionController");

QuizAppDelegate *delegate =
(QuizAppDelegate *)[[UIApplication sharedApplication] delegate];

[delegate.navController pushViewController:questionController animated:YES]; <== bad access

[questionController release];


So, I think I'm incorrectly releasing; it's doing one of the "narc" operations - i.e., new, allocate, release, copy. So, let's get rid of that.

Ok - progress. It's not crashing. But there are a couple of problems. One is that the numbers aren't properly randomized - they always come up in the same order. Let's tackle that one right now.

Ok, well, the obvious problem is that I'm not randomizing them. Here's the code:



appState.shuffledArrayIndex = 0;

NSInteger startNum = [Utils getStartNum];
NSInteger endNum = [Utils getEndNum];

NSMutableArray* questionDictKeys = [NSMutableArray array];

for (int i = startNum; i <= endNum; i++){

NSNumber *myKey = [NSNumber numberWithInt:i];
NSLog(@"QuizAppDelegate, myKey: %d", [myKey intValue]);

[questionDictKeys addObject:myKey];
}

//NSArray *keys = [appState.questionDict allKeys];


appState.shuffledQuestionDictKeyList = [questionDictKeys shuffledArray];

for (int i = 0; i < [appState.shuffledQuestionDictKeyList count]; i++){
NSLog(@"shuffledQuestionDictKeyList[i]: %d", [[appState.shuffledQuestionDictKeyList objectAtIndex: i] intValue]);

}


Randomization was clearly left as a "I'll get around to it when it's time" item. Well, it's time. Plus, this really needs to be moved out of the app delegate and into the StartController.

Well, I'll be darned. That seems to have fixed up all sort of problems. It's showing all three instead of just one, and it seems to be mixing things up. Here's the code:

- (IBAction)openQuestionController
{
NSLog(@"openQuestionController");

QuizAppDelegate *delegate =
(QuizAppDelegate *)[[UIApplication sharedApplication] delegate];

appState.shuffledArrayIndex = 0;

NSInteger startNum = [Utils getStartNum];
NSInteger endNum = [Utils getEndNum];

NSMutableArray* questionDictKeys = [NSMutableArray array];

for (int i = startNum; i <= endNum; i++){

NSNumber *myKey = [NSNumber numberWithInt:i];
[questionDictKeys addObject:myKey];
}

appState.shuffledQuestionDictKeyList = [questionDictKeys shuffledArray];


[delegate.navController pushViewController:questionController animated:YES];

}



Oh, yeah, I did handle the randomization. Good, yeah it was that adding of functionality to the NSArray - I forget the term for it - but here's the code:

@implementation NSArray(Shuffle)
-(NSArray *)shuffledArray{

NSMutableArray *array = [NSMutableArray arrayWithCapacity:[self count]];

NSMutableArray *copy = [self mutableCopy];
while ([copy count] > 0)
{
int index = arc4random() % [copy count];
id objectToMove = [copy objectAtIndex:index];
[array addObject:objectToMove];
[copy removeObjectAtIndex:index];
}

[copy release];
return array;
}
@end



Ok, onward and upward.

No comments:

Post a Comment