Day 35 Challenge

Hello,

I made it to day 35 of the Hacking with SwiftUI course and I am stuck. For those that don't remember the challenge involves making an edutcation app for multiplication tables. The part that I am sturggling with is generating the questions. Perhaps I am approaching this the wrong way, hence the post. What I am trying to do is creating a Struct that takes 2 inputs, the type of multiplication table and number of questions, and based on these inputs it generates a dictionary where the questions are the keys and the values are the answers, something like:

``````{
"What is 5 X 5?": 25,
"What is 5 X 2?": 10
}``````

I have started creating it so:

``````struct QuestionBank {
let multiplicationTable: Int
let numberOfQuestions: Int

var allQuestions = [String: Int]()

mutating func generateQuestionBank() {
for i in 1...numberOfQuestions {
// append to allQuestions
}
}
}``````

However this causes a few problems, first of all allQuestions becomes an input variable, I tried to switch to a computed property but that didn't really work. Is there anything I could try to get this to work?

1

What I am trying to do is creating a Struct that takes 2 inputs, the type of multiplication table and number of questions, and based on these inputs it generates a dictionary where the questions are the keys and the values are the answers....

Excellent question! Also +1 for taking a BIG problem and breaking it down into several smaller problems.

Big Problem: Create a multi-purpose Multiplication Table struct. Small Problem 1: Accept number of question and Multiplication table value.

Analysis:

``````struct QuestionBank {
let multiplicationTable: Int  // accept user’s selected table
let numberOfQuestions: Int // accept user’s desire for punishment
// ………. snip ………….``````

Looks like Small Problem 1 is complete.

Small Problem 2: Generate Questions Analysis:

``````var allQuestions = [String: Int]()  // create an empty dictionary
mutating func generateQuestionBank() {
for _ in 1...numberOfQuestions {
// what to do here?
// BREAK your big problem into several smaller problems!
}``````

You have another big problem, you need to break into smaller problems. What parts do you need to solve your big problem?
You probably need the QUESTION, which is made up of two parts, the given times table, and a random integer. Then you want to pack these into a string. Of course, you also want the answer. These smaller parts are then packed into a dictionary.

``````let questionInt = Int.random(0…12) // pick a random number between 1 and 12.
let question = "\(multiplicationTable) x \(questionInt) = "  // a string looks like  “6 x 9 =“
let answer = questionInt * multiplicationTable
// Now you have the smaller problems solved, assemble them to solve your larger problem.
allQuesions[question] = answer  // this is how you add something to a dictionary.``````

Here’s sample code to run in Playgrounds:

``````struct QuestionBank {
let multiplicationTable: Int
let numberOfQuestions: Int

var allQuestions = [String: Int]()

mutating func generateQuestionBank() {
for _ in 1...numberOfQuestions {
let questionInt = Int.random(in: 0...12) // multiply multiplicationTable x questionInt
let question = "\(multiplicationTable) x \(questionInt) = "  // a string
let answer = questionInt * multiplicationTable
}
}
}

var sixTimesTable = QuestionBank(multiplicationTable: 6, numberOfQuestions: 10)
sixTimesTable.generateQuestionBank()

var nineTimesTable = QuestionBank(multiplicationTable: 9, numberOfQuestions: 5)
nineTimesTable.generateQuestionBank()``````

By breaking your big problem into smaller solvable problems, you’ve found a solution.

Or have you?

When you review the output, are you concerned? It seems the dictionary might have duplicate entries in it.

2

Thank you for the breakdown and explanation. I was guessing it was going to look like that but wasn't sure how to start (I come from a Python background which is not really a Type-Safe language). I applied the Struct to my code and now it works and I am able to generate questions based on the user input... however this resulted in other issues I did not plan for.

A dictionary is unordered so I cannot go through it one-by-one displaying a question then moving on to the next. I will spend some time now trying to figure out how to work around this, maybe I will need to change the logic a bit.

Anyway, until then, just wanted to say Thank You once again for the assistance in helping me get past the first hurdle :)

1

Andy shares experience with Python:

A dictionary is unordered so I cannot go through it one-by-one displaying a question then moving on to the next. I will spend some time now trying to figure out how to work around this, maybe I will need to change the logic a bit.

Something to think about.... Stepping through an unordered dictionary element by element, excluding duplicates, and moving to the next, then attempting to push bits to a display is very procedural. Swift is a functional programming language. Try a different tactic.

What is your phone doing right now? Processing temperature? Listening for "Hey Siri!"...determining your latitude and longitude.... counting your steps....checking battery status...syncing with iCloud.... checking for new email messages....calculating 45,000 positions of your face for authentication...

It's doing exhausting work, but not even breaking a sweat!

So consider, hear me out, consider doing something outrageou! Why not create a bank array that contains Question data structures for each times table element from 1 up to 12. Your iPhone will probably be insulted when asked to perform such a trivial task. Pffffft.

Then, if the user just asks for 9 quiz questions, ask your bank array to return 9 random elements and load them into a quiz array? Base your user's interface off the quiz array, not the bank array. If your user changes their mind and asks for 6 quiz questions, it's easy to recalculate your quiz array. And your interface will update immediately to reflect the new contents of the quiz array.

Have a look in the documentation for array! Is there a method to shuffle the contents of an array? Is there a way to return the first X elements? Luke! USE the FORCE FUNCTIONS!

PS: I know! There are lots of reasons why Swift shouldn't be considered a functional programming language. Just humor me.

1

I am currently working on this challenge and have found the discussion very useful.

Some additional question I have are:

1) I have created a Questions struct to create a bank array of questions with answers which is separate from the ContentView struct.

``````struct Questions {
var questionsArray = [String]()

mutating func buildQuestionsArray() {
for i in 2...12 {
for j in 1...12 {
questionsArray.append("What is \(i) times \(j)?")
questionsArray.append("The answer is \(i * j).")
}
}
}
}``````

How do I create the bank array so it is available in the ContentView struct? If I try to create it in ContentView I get the below errors...

``````struct ContentView: View {
@State private var tableSelected = 2
@State private var questionOptions = [5, 10, 20]
@State private var questionsWanted = 5
@State private var gameActive = false
@State private var answer = ""
@State private var alertTitle = ""
@State private var alertMessage = ""
@State private var scoreTitle = ""
@State private var showingAlert = false
@State private var showingScore = false
@State private var userScore = 0

var myTimesTable = Questions()
myTimesTable.buildQuestionsArray()     <-------Invalid redeclaration of 'myTimesTable()'

var body: some View {
Form {
Section {
Stepper("\(tableSelected)", value: \$tableSelected, in: 2...12)``````

2) How to extract the question and answers into a quiz array that matches user settings?

If the user selects, for example, review of the 3 times table and 5 questions and I extract the entire 3 times table questions and answers (I know their positions in the bank array) I simply can't shuffle the quiz array because the questions and associated answers are sequential in the quiz array. Paul hints on using a state property called questionNumber or similar, which is an integer pointing at some position in your question array, but I'm struggling how to make that work.

Any insights would be much appreciated.

SAVE 50% To celebrate WWDC22, all our books and bundles are half price, so you can take your Swift knowledge further without spending big! Get the Swift Power Pack to build your iOS career faster, get the Swift Platform Pack to builds apps for macOS, watchOS, and beyond, or get the Swift Plus Pack to learn advanced design patterns, testing skills, and more.

Sponsor Hacking with Swift and reach the world's largest Swift community!