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
}
}
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 !"
}
}
}
}
}
}
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.
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
}
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