Xcode Swift: Converting Arrayed String With If Statement - swift

This is a simple quiz app with a label and four buttons. I want code in the action button to execute by referencing the question in the if statement. (The problem with referencing the answer tag is that there are only four buttons, but more than four questions.) The code below gives an error that you can't use the binary operator. How can I make this work?
struct Question {
var Question : String!
var Answers : [String]!
var Answer : Int!
}
var Questions = [Question]()
var QNumber = Int()
var AnswerNumber = Int()
Questions = [Question(Question: "One", Answers: ["", "", "", ""], Answer: 0),
Question(Question: "Two", Answers: ["", "", "", ""], Answer: 1),
Question(Question: "Three", Answers: ["", "", "", ""], Answer: 2),
Question(Question: "Four", Answers: ["", "", "", ""], Answer: 3),
Question(Question: "Five", Answers: ["", "", "", ""], Answer: 0),]
func PickQuestion(){
if Questions.count > 0{
QNumber = 0
QLabel.text = Questions[QNumber].Question
AnswerNumber = Questions[QNumber].Answer
for i in 0..<Buttons.count{
Buttons[i].setTitle(Questions[QNumber].Answers[i], for: UIControlState.normal)
}
Questions.remove(at: QNumber)
}
#IBAction func Btn4(_ sender: Any) {
if(Question == "Five") {
//CODE THAT NEEDS TO EXECUTVE
} else if(Question == "Four") {
//EXECUTE A DIFFERENT CODE
}

Your question is super unclear and it looks like you would benefit from re-structuring your logic. That said, if this is a simple quiz app and you have a few buttons with tags 0, 1, 2 and 3 then you should simply be able to compare the Question's Answer property with the buttons tag and avoid comparing any strings altogether.
It's also not clear from your question how the "current question" is selected, so you may want to firm that one up too, I'd recommend storing the object in a var somewhere so you can do something like the following...
var currentQuestion:Question!
// Get the first question or something.
currentQuestion = Questions.first
#IBAction func buttonTapped(sender: UIButton) {
if sender.tag == currentQuestion.Answer {
print("You are a winner")
// Time to get a new question son.
}
}
The above code is untested and I hope it doesn't just confuse you further, however, in the current format your question may be closed as it is not completely clear what you are asking.
Edit:
Thanks for updating your question, It looks now like you are trying to compare the Question struct against the String "Five". these two objects are not comparable.
To make your code work you should use the AnswerNumber variable that you have made and check if the number matches like so.
#IBAction func Btn4(_ sender: Any) {
if AnswerNumber == 4 {
print("Correct Answer")
//CODE THAT NEEDS TO EXECUTVE
} else {
print("Wrong Answer")
//EXECUTE DIFFERENT CODE
}
}
Assuming you have an IBAction for each button you will need to repeat this for each, so Btn5 would look like this.
#IBAction func Btn5(_ sender: Any) {
if AnswerNumber == 5 {
...
Edit:
After chatting away, we figured out that you needed a custom action for each question (if the correct answer was selected). this took the form of an mp3 file that was played depending on which question it was.
We came to the conclusion that following the existing structure you should add another variable to hold the mp3 in the Question struct but also for the current question as below.
struct Question {
var Question : String!
var Answers : [String]!
var Answer : Int!
var audioFile: String!
}
var AnswerMP3 = ""
Then when we set the current question alongside AnswerNumber we can set the mp3 like so.
AnswerMP3 = Questions[QNumber].audioFile
Then in this way you do not need to have hardcoded actions for each question. the buttons simply pass the correct mp3 on to another method that plays the audio file.
if AnswerNumer == 4 {
playMP3File(AnswerMP3)
}
func playMP3File(fileName:String) {
// user the fileName to play the audio file.
}

Related

make a button display an element each time its pressed

I am new to Swift, and I am trying to make a basic question answer app. I want to set up the question button so that whenever I press it, it displays one question, and if I press it again, it shows another question. I have a separate button that will show the answer but I need to connect to which ever question is being asked. How do I do this?
Here is what I have so far, it just asks the question at random, but I want to be able to ask all the questions, not just whatever it picks, I am not sure how to do that though.
#IBAction func question(_ sender: Any) {
let questions = ["What is your name?", "What is your favourite colour?",
"What is your favourite movie?", "What is your major?"]
let randomQuestion = questions.randomElement()
qLabel.text = randomQuestion
}
You can try
var index = 0 // add a current index of the shown question
let questions = ["What is your name?", "What is your favourite colour?",
"What is your favourite movie?", "What is your major?"]
#IBAction func question(_ sender: Any) {
if index < questions.count {
qLabel.text = questions[index]
index += 1
}
else {
// end of questions
}
}

Role Game Effect/Potion Generator in Swift

First of all, excuse me for my (sometimes) bad English, I'm french. I'm actually working on a role game project. The goal is to create a little macOS software (a generator) using Swift and Xcode that can create a potion (an effect associated with a potency) (like : "Fortify Speed 7/10") from multiple parameters. The app allows the user to enter two parameters : ingredients (selected in pop-up menus) and a dice roll (put in a text field). If those two (or more) ingredients have an effect in common, the soft makes an addition of the value of both effects and return this : ""effect in common" + (value of the 1st ingredient effect + value of 2nd ingredient effect)". The result can change during the operation depending on the dice roll, but it doesn't matter here.
Here is an exemple to understand what I'm saying :
1st ingredient : "Cat's Claw Bark" -> Resist Lightning (4/10); Resist Psychic (3/10); Acid Damage (3/10); Fear (3/10); Invisibility (1/10).
|| 2nd ingredient : "Grape Holly" -> Cure Disease (5/10); Resist Cold (4/10);
Heighten Medicine (4/10; Resist Lightning (3/10); Force Damage (2/10.
Because both ingredients have an effect in common (Resist Lightning), the soft returns that effect with an addition of the potency of the two effects.
So it returns : "Resist Lightning (7/10)"
Here is my first question : How can I convert this into Swift code ? I've tried many ways but nothing useful. I tried to use arrays, dictionaries, arrays into dictionaries, but I'm still facing the same problem : How can I attribute multiple parameters (effects in this case) and types (String for the name of the effect and Int for its potency) to an instance ? (If it's the right question). My second question is : How can I compare keys (not values) of a dictionary to match a result ?
Maybe like this, using a dictionary, but I'll need to display in the result not only the value of the key in the dictionary, but the key itself. Also, I'll need to compare the keys, not the values :
let grapeHolly: [String: Int] = ["Cure Disease": 5, "Resist Cold": 4, "Heighten Medicine": 4, "Resist Lightning": 3, "Force Damage": 2]
And by doing that I get a "Cannot use instance member 'grapeHolly' within property initializer" error. And if I put that line inside the body of a 'viewDidLoad()' function, it isn't recognize by the code that is not inside the function.
The UI of the app
To be clear and comprehensible, I want that when the user selects two or more ingredients from the second pop-ups menu (the first line of pop-ups are made to categorize ingredients into three categories "Common/Uncommon/Rare"), and when he push the "Make a potion" button, the result text field displays the result of the combination of both effects values, if they have an effect in common of course.
Tell me if you need me to be more precise, I'll be very happy to find help :)
Here is the code (don't care about the length of the ingredients list) :
import Cocoa
class ViewController: NSViewController {
#IBOutlet weak var ingredientRarityNorthlands: NSPopUpButton!
#IBOutlet weak var ingredientListNorthlands: NSPopUpButton!
#IBAction func ingredientRarityNorthlands(_ sender: NSPopUpButton) {
if ingredientRarityNorthlands.titleOfSelectedItem == "Common" {
ingredientListNorthlands.removeAllItems()
ingredientListNorthlands.addItems(withTitles: ingredientListNorthlandsCommon)
}
if ingredientRarityNorthlands.titleOfSelectedItem == "Uncommon" {
ingredientListNorthlands.removeAllItems()
ingredientListNorthlands.addItems(withTitles: ingredientListNorthlandsUncommon)
}
if ingredientRarityNorthlands.titleOfSelectedItem == "Rare" {
ingredientListNorthlands.removeAllItems()
ingredientListNorthlands.addItems(withTitles: ingredientListNorthlandsRare)
}
}
let ingredientListNorthlandsCommon = ["Black Pepper", "Bolean Violet", "Brittlebush Flower", "Brittlebush Resin", "Butterfly Moss", "Cardamom", "Cinnamon", "Cloves", "Colic Yellowcress", "Comb Mint", "Coriander (Leaves)", "Coriander (Seeds)", "Cork Tree Bark", "Crow Hood", "Cumin (Seeds)", "Desert Shrub", "Eucalyptus (Oil)", "Eucalyptus (Gum)", "Eucalyptus (Leaves)", "Eucalyptus (Seeds)", "Fire Itchweed", "Four-Leafed Colwort", "Frukmoot", "Ginger (Root)", "Jasmine (Flower)", "Life's Collard", "Lotus (Petals)", "Lotus (Seeds)", "Mango (Leaves)", "Mango (Taproot)", "Marigold (Flower)", "Marigold (Leaves)", "Mustard (Flower)", "Mustard (Greens)", "Mustard (Seeds)", "Nutmeg (Oil)", "Nutmeg (Seed)", "Radiant Azolla", "Red Chili (Seeds)", "Wall Snakeberry"]
let ingredientListNorthlandsUncommon = ["Aloe Vera", "Ash Gallberry", "Baby Zinnia", "Black Salt", "Buzzard Bile", "Corea Mint", "Dead Sage", "Dog Tongue", "Fennec Fox Droppings", "Giant Lizard Venom", "Marsupial Wolf Blood", "Noxious Laurel", "Ocort", "Orange Thyme", "Pale Penny Gilliflower", "Phoenix Briar", "Pocan Hemp", "Prickly Cane", "Serpent Rye", "Shivering Laurel", "Snage", "Two-Tongued Scorpion Tail", "Viper Venom"]
let ingredientListNorthlandsRare = ["Blackheart Flower", "Burrowing Vee Spider", "Jee Redzin Scorpion Eggs", "Kreetlee Leaves", "Olaart Buds", "Smouse Oil", "Wretch Salts", "Zettin Seeds"]
#IBAction func makeAPotion(_ sender: NSButton) {
if potionButton.isEnabled {
resultField.stringValue = result()
}
}
func result() -> String {
return "\(effect) \(value)"
}
}
Ps: I think it's not necessary but I put here the dice roll system :
var firstEffect = 10..<12
var secondEffect = 12..<15
var thirdEffect = 15..<20
var fourthEffect = 20..<25
var fifthEffect = 25...
var firstEffectEnabler: Bool = false
var secondEffectEnabler: Bool = false
var thirdEffectEnabler: Bool = false
var fourthEffectEnabler: Bool = false
var fifthEffectEnabler: Bool = false
#IBAction func diceRoll(_ sender: NSTextField) {
if diceRoll.stringValue == "\(firstEffect)" {
firstEffectEnabler = true
}
if diceRoll.stringValue == "\(secondEffect)" {
secondEffectEnabler = true
}
if diceRoll.stringValue == "\(thirdEffect)" {
thirdEffectEnabler = true
}
if diceRoll.stringValue == "\(fourthEffect)" {
fourthEffectEnabler = true
}
if diceRoll.stringValue == "\(fifthEffect)" {
fifthEffectEnabler = true
}
}
EDIT : So I tried this but I think it's a bit messy and not very optimized, and I don't really know if it could work. Also, there's still two problems : I don't know how to display the string "Grape Holly" in the ingredient list array and in the pop-up menu instead of "grapeHolly", and how to fix the "potency = grapeHolly[?]" line :
lazy var grapeHolly = ["Cure Disease": 5, "Resist Cold": 4, "Heighten Medicine": 4, "Resist Lightning": 3, "Force Damage": 2]
lazy var effect = Array(grapeHolly.keys)
var result: String = ""
lazy var potency = grapeHolly[]
func compare() {
func resultNorthlands() {
if ingredientListNorthlands.selectedItem?.doesContain(effect) == ((ingredientListMettina.selectedItem?.doesContain(effect))! || (ingredientListIsjord.selectedItem?.doesContain(effect))! || (ingredientListKaedmyr.selectedItem?.doesContain(effect))! || (ingredientListCouchant.selectedItem?.doesContain(effect))! || (ingredientListBlastlands.selectedItem?.doesContain(effect))!) {
var result = "\(effect)"
}
}
I think something could work but I get an error "Cannot subscript a value of type'[String: Int]' with an index of type '[String]'" on the "lazy var potency = grapeHolly[effect]" line. I don't really understand why... "dictionary[key]" isn't the way to get a key's value in a dictionary ? Also, I need to enter "grapeHolly" instead of the "Grape Holly" string in my ingredient list, do someone knows a way to fix this ?
(I made a 'grapeHollys' dictionary with orthographical mistakes except on the "Cure Disease" effect to match both effects lines as shown in the 'compare()' function)
About the 'compare()' function : I repeated as many times as the number of ingredient list, but changed the name of the first ingredient list (ingredientListNorthlands in this case) for each function repetition, to compare every ingredient list before the '==' operator with the other lists, so it's a bit long and repetitive, and I know it's not a good habit for a programmer to repeat itself, but that's all I've found yet.
But for now I can't build because of the error, so I can't test the efficiency of the code, that's why I'm asking you a bit of help :)
Here is the code :
//Properties
var result: String = ""
lazy var potency = grapeHolly[effect]
lazy var effect = Array(grapeHolly.keys)
lazy var grapeHolly = ["Cure Disease": 5, "Resist Cold": 4, "Heighten Medicine": 4, "Resist Lightning": 3, "Force Damage": 2]
lazy var grapeHollys = ["Cure Disease": 5, "Resist Cld": 4, "Heighten Mediine": 4, "Resist Lightnng": 3, "Force Damge": 2]
// Compare Function
func compare() {
func resultNorthlands() {
if ingredientListNorthlands.selectedItem?.doesContain(effect) == ((ingredientListMettina.selectedItem?.doesContain(effect))! || (ingredientListIsjord.selectedItem?.doesContain(effect))! || (ingredientListKaedmyr.selectedItem?.doesContain(effect))! || (ingredientListCouchant.selectedItem?.doesContain(effect))! || (ingredientListBlastlands.selectedItem?.doesContain(effect))!) {
var result = "\(effect) \(potency1 + potency2)"
}
}
//Potion Button
#IBAction func makeAPotion(_ sender: NSButton) {
compare()
if potionButton.isEnabled {
resultField.stringValue = result
}
}
Problem solved ! The solution was so obvious that I didn't think about it directly, the for-in loops ! I hope this will help anybody facing the same issue. Here is the corresponding code :
var selection = [
catClawBark: ["Resist Lightning": 5, "Resist Damage": 8],
grapeHolly: ["Resist Lightning": 6, "Resist Damage": 2]
]
for (ingredient, keys) in selection {
for key in keys {
for (ingredient2, keys2) in selection {
for key2 in keys2 {
if ingredient != ingredient2 {
if key.key == key2.key {
result = "You created a potion !\n---> \(key.key) \(key.value + key2.value) <---"
}
else {
result = "No match. Check the ingredients selected or retry when you have more !"
}
}
}
}
}
}

Swift make user selection on picker view the title for a button

So, I'm not sure if I've been staring at my code so long I've become dumb or if this is a bit too advanced for my current skills. I am trying to make a pickerview pop up when the user presses a button using DPPickerManager and when the user selects a color the title of the button is supposed to change to what was selected by the user. Flowing the directions I was able to link the button and pickerview but I can't get the button title to change. Here's my code:
#IBAction func colorPicker(_ sender: UIButton) {
let condition = ["Blue", "Black", "Green", "Orange", "Purple"]
DPPickerManager.shared.showPicker(title: "Strings Picker", selected: "Value 1", strings: condition) { (value, ind, cancel) in
if !cancel {
//sender.titleLabel.text = value![index].text
print(value as Any)
}
}
}
I keep getting this error: Cannot convert value of type '(Any) -> Int' to expected argument type '(UnboundedRange_) -> ()' and I think its because of the value's index but I am unsure. Can someone please help me?
I have used your code and it's working fine for me.
#IBAction func btnActionTapped(_ sender: UIButton) {
let condition = ["Blue", "Black", "Green", "Orange", "Purple"]
DPPickerManager.shared.showPicker(title: "String Picker", selected: "Value 1", strings: condition) { (value, index, cancel) in
if !cancel {
if let value = value {
sender.setTitle(value, for: .normal)
print(value)
}
}
}
}
I just changed following code to get value instead of optional value.
if let value = value {
print(value)
}
I’m getting string value there and print fine in console.

textual questionnaire system - swift 3

This question is about building a textual questionnaire system using swift 3.
Assuming we have (n) questions, the user will be asked one question at the time, replying with text (using UITextField).
if the answer is something that is expected (YES/NO for example) the code will carry on to the next question, otherwise it will try to give some more elaborate question with possible answers (see code below).
The idea is having some kind of an array of dictionaries, each dictionary (questionItem) contains a single question/answer data...
Question: even if the following code works fine, I feel that this is not the most scalable nor elegant solution. Thus my question is more about your ideas regarding code design.
how can one make a code such as this - that is scalable for multiple questions.
static var questionItem = [
"question": "Is the sky blue?",
"answer": "yes",
"afterAnswer": "question #2",
"explanation": "simply answer: yes or no"
]
class func getAnswer(answer: String) -> String
{
let expectedAnswer = questionItem["answer"]
let isEqual = (answer == expectedAnswer)
var respond = "undifined"
if isEqual {
// go for next question ( questionItem["afterAnswer"] )
respond = "ok, going to the next question"
} else {
// didn't got the answer I was waiting for, going to show some longer explanation
respond = questionItem["explanation"]!
}
// respond
return respond
}
You can create a struct with your desired information, then create a Trivia of Type Int: YourStruct to manage all the different questions answers and explanations, like my example below, let me know is its clear enough:
struct QuestionsAndAnswers{
var question: String = ""
var answer: String = ""
var explanation: String = ""
}
var trivia: [Int: QuestionsAndAnswers] = [:]
trivia = [1: QuestionsAndAnswers.init(question: "Your First Question", answer: "Your Fist Answer", explanation: "Your First explanation")]
trivia = [2: QuestionsAndAnswers.init(question: "Your Second Question", answer: "Your Second Answer", explanation: "Your Second explanation")]
func getAnswer(answer: String, quesiontNumber: Int) -> String
{
let expectedAnswer = trivia[quesiontNumber]?.answer
let isEqual = (answer == expectedAnswer)
var respond = "undifined"
if isEqual {
// go for next question ( questionItem["afterAnswer"] )
respond = "ok, going to the next question"
} else {
// didn't got the answer I was waiting for, going to show some longer explanation
respond = (trivia[quesiontNumber]?.explanation)!
}
// respond
return respond
}

How do I correctly use map & zip to compare properties in my array of Structs?

I am using the following line to compare the correctAnswers in a quiz to the answers that the user submitted.
It returns an array of bools, which I would then search through and count how many true and how many false they got (true = correct and false = incorrect).
let totalResults = map(zip(correctAnswers, userAnswers)){$0.0 == $0.1}
I have all my quiz information stored in an array of structs e.g
struct questionInfo {
var question : String!
var answer : Bool!
var userAnswer : Bool!
var explanation : String!
init(question: String, answer: Bool, explanation: String!) {
self.question = question
self.answer = answer
self.explanation = explanation
}
}
// These are the questions that will be shuffled before the quiz begins
var quizQuestion =
[
questionInfo(question: "Question 0", answer: true, explanation: ""),
questionInfo(question: "Question 1", answer: true, explanation: ""),
questionInfo(question: "Question 2", answer: true, explanation: ""),
questionInfo(question: "Question 3", answer: true, explanation: ""),
questionInfo(question: "Question 4", answer: true, explanation: "")
]
How would I input the info from the array of structs into my map & zip line. I tried appending all the answers to an array using a for loop but it seems very messy.
For clarification I want to do something like this:
let totalResults = map(zip(quizQuestion[x].answer, quizQuestion[x].userAnswer)){$0.0 == $0.1}
You don't need zip() if all information is in the single quizQuestion
array, only map():
let totalResults = map(quizQuestion) { $0.answer == $0.userAnswer } // [Bool]
Then you can count the number of correct answers with reduce():
let numberOfCorrectResults = reduce(totalResults, 0) { $0 + Int($1) } // Int
This is the Swift 1.2 syntax, for Swift 2 from Xcode 7 beta it would be
let totalResults = quizQuestion.map { $0.answer == $0.userAnswer } // [Bool]
let numberOfCorrectResults = totalResults.reduce(0) { $0 + Int($1) } // Int