Finding specific elements of array with images - swift

I have a program that displays a random card when you click the screen, and then removes that card from the card deck. But I also want to check if the random card is either of the picture cards in the deck (so jack, king, queen or ace), and then do some stuff if it is one of those. Anyone know how I can do it? When I try to check if the random card is equal to for example cardDeck[0] (the first card in the deck is a picture card), I get an error:
Cannot assign value of type 'UIImage' to type 'Int'
Thanks for all help!
My code looks like this:
var cardDeck = [card1,card2,card2 etc....]
var randomCard: Int = 0
var cardPosition = 0
//row1card1
#IBAction func row1card1tapped(_ sender: UITapGestureRecognizer) {
randomCard = Int.random(in: 0...51)
if cardDeck.count > randomCard + 1 {
if randomCard == cardDeck[0] {
//do stuff here
} else {
row1card1.image = cardDeck[randomCard+1]
cardDeck.remove(at: randomCard)
print("removed:" + "\(cardDeck[randomCard])")
score += 2
currentPoints.text = "\(score)"
}

Your randomCard variable is an Int and you’re trying to compare that with an element from cardDeck which is an image. That’s why you are getting the above exception.
if randomCard == 0 {
//do stuff here
}

Related

UITextField being treated as nil when it isn't

I have a piece of code intended to allow a user to change which unit of weight they are using. If they've already entered a value it is automatically converted between kilograms and pounds. It is changed by tapping on a UISegmentedControl where segment 0 is kilogram and segment 1 is pound.
Changing the first time works perfectly regardless of if the user went from kilogram to pound or vice versa. However, upon attempting to make a second conversion the program immediately crashes claiming that the value in the text field containing weight is nil even though it clearly contains text.
Here is my code as of now:
#IBAction func unitChanged(_ sender: UISegmentedControl) {
if let text = weightInput.text, text.isEmpty {
//Does nothing since there is no weight to change the unit of
}
else {
let weight: Int? = Int(weightInput.text!)
var weightDouble: Double = Double(weight!)
if (weightTypeInput.selectedSegmentIndex == 0) {
//The user is trying to change from pounds to kilograms
weightDouble = weightDouble * 0.45359237
}
else {
//The user is trying to change from kilograms to pounds
weightDouble = weightDouble * 2.2046226218
}
weightInput.text = String(weightDouble)
}
}
Here is what the code looks like in practice
Finally here is the error message I get:
Thread 1: Fatal error: Unexpectedly found nil while unwrapping an Optional value
If I put a default value for weightDouble it is always used for all subsequent conversion attempts. Has anyone here encountered a similar issue? I attempted to search online but I couldn't find anything to help.
Are you sure that the text value of your TextField is nil? Since you're simply checking it in the first if in my opinion that would not be the case.
Int can't parse numbers with a floating-point in them. It returns nil when you do this. You might want to parse it into a Double first and then convert it to Int.
I think your code should be as follows:
#IBAction func unitChanged(_ sender: UISegmentedControl) {
guard let text = weightInput.text, !text.isEmpty, var weightDouble = Double(text) else { return }
if (weightTypeInput.selectedSegmentIndex == 0) {
//The user is trying to change from pounds to kilograms
weightDouble = weightDouble * 0.45359237
}
else {
//The user is trying to change from kilograms to pounds
weightDouble = weightDouble * 2.2046226218
}
weightInput.text = String(Int(weightDouble))
}

how can i solve this "Cannot subscript a value of type `[[String]]` with an index of type `UInt32`"

i'm having a problem about this UInt32 thing,
the "answer" in my button is having an error about this "Cannot subscript a value of type [[String]] with an index of type UInt32"
let answers = [["1. After the exam, I felt too exhausted and famished to eat my foods.","2. I could eat a horse, I am a famish now.","3. I famished my stomach next time you treat me to a meal out.","4. I will bring lots of pizza, that's famish."],["Would","Has to","Must","Could"]]
var rightanswerplacement:UInt32 = 0
rightanswerplacement = arc4random_uniform(2)+1
var button:UIButton = UIButton()
var x = 1
for i in 1...3{
button = view.viewWithTag(i) as! UIButton
if (i == Int(rightanswerplacement)){
button.setTitle(answers[rightanswerplacement][0], for: UIControlState.normal)
}
else{
button.setTitle(answers[rightanswerplacement][x], for: UIControlState.normal)
x = 2
}
currentquestions += 1
}
Use Int for subscripts.
Note: I removed the views to test the correctness of Int.
let answers = [["1. After the exam, I felt too exhausted and famished to eat my foods.","2. I could eat a horse, I am a famish now.","3. I famished my stomach next time you treat me to a meal out.","4. I will bring lots of pizza, that's famish."],["Would","Has to","Must","Could"]]
var rightanswerplacement: Int = 0
rightanswerplacement = Int(arc4random_uniform(2)) + 1
var x = 1
for i in 1...3 {
if (i == Int(rightanswerplacement)) {
print(answers[rightanswerplacement][0])
} else {
print(answers[rightanswerplacement][x])
x = 2
}
}
Output
Would
Has to
Must

"Attemped to add a SKNode which already has a parent:" in Repeat Loop. Any simple work around?

I am pretty Newbie to programming. And I am trying to pile up the random blocks dynamically till it hits the upper frame. But it seems that Swift doesn't let me to do so. Did I miss anything please? Any input are appreciated.
let blocks =[block1,block2,block3,block4,block5,block6,block7,block8,block9,block10,block11,block12]
var block:SKSpriteNode!
let blockX:Double = 0.0
var blockY:Double = -(self.size.height/2)
repeat{
block = blocks.randomBlock()
block.zPosition = 2
block.position = CGPoint(x:blockX, y:blockY)
block.size.height = 50
block.size.width = 50
self.addChild(block)
blockY += 50
} while( block.position.y < self.size.height)
extension Array {
func randomBlock()-> Element {
let randint = Int(arc4random_uniform(UInt32(self.count)))
return self[randint]
}
}
you need to have someway of tracking which blocks have been selected and ensure that they don't get selected again. The method below uses an array to store the indexes of selected blocks and then uses recursion to find a cycle through until an unused match is found.
private var usedBlocks = [Int]()
func randomBlock() -> Int {
guard usedBlocks.count != blocks.count else { return -1 }
let random = Int(arc4random_uniform(UInt32(blocks.count)))
if usedBlocks.contains(random) {
return randomBlock()
}
usedBlocks.append(random)
return random
}
in your loop change your initializer to
let index = randomBlock()
if index > -1 {
block = blocks[index]
block.zPosition = 2
block.position = CGPoint(x:blockX, y:blockY)
}
remember that if you restart the game or start a new level, etc. you must clear all of the objects from usedBlocks
usedBlocks.removeAll()

Issue with checking new integer against previous one

Im attempting to make something similar to the high low game. So far i can get a new integer between 1-25 to be generated.
Ive tried to write a function that when you press the 'lower' button it checks the new integer against the previous one, and if it is less then text is displayed below saying 'You Were Correct' and updates the users score +1.. and if wrong 'You Were Wrong' displays instead and score is reset to 0.
Whenever i press the lower button it gives me a new int but score is not updated and the message doesn't display. This is my first real attempt at making this so bear with me :)
Lower Button
#IBAction func lower(sender: AnyObject) {
var newNumber = randomIntBetween(2, high: 26)
var oldNumber: Int?
func lowerNumber() -> Int {
if newNumber <= oldNumber {
correctWrong.text = "You Were Correct!"
score.text = "Score: \(countWin++)"
} else {
correctWrong.text = "You Were Wrong!"
score.text = "Score: \(countLose)"
}
return newNumber
}
randomNumbers.text = "\(newNumber)"
}
Random Number Function
func randomIntBetween(low:Int, high:Int) -> Int {
let range = high - (low - 1)
return (Int(arc4random()) % range) + (low - 1)
}
Variables/Constants Used
var countWin = 0
let countLose = 0
Thanks
As far I can see if your code it's formatted correctly you have a nested function but you aren't calling it inside your function so it's impossible that the function lowerNumber() will be called. You need to call the function like the following code:
#IBAction func lower(sender: AnyObject) {
var newNumber = randomIntBetween(2, high: 26)
var oldNumber: Int?
func lowerNumber() -> Int {
if newNumber <= oldNumber {
correctWrong.text = "You Were Correct!"
score.text = "Score: \(countWin++)"
} else {
correctWrong.text = "You Were Wrong!"
score.text = "Score: \(countLose)"
}
return newNumber
}
let newValue = lowerNumber()
randomNumbers.text = "\(newValue)"
}
Nevertheless, nested functions are closures that have a name and can capture values from their enclosing function so you need to be carefully with its use. I recommend this article of #AirSpeedVelocity to learn more about the closures and its capture values A Basic Tutorial on Functions and Closures in Swift
I hope this help you.

Cannot change tuple in an array

I'm trying to change a tuple in an array , however ,when I try
emo = (type:emo.type,strength:increaseStrength(emo.strength))
it gives me error
"cannot assign to 'let' value 'emo'
here is my code :
var emotions : [(type : String, strength: Int)] = [("happy",0),("scared",0),("tender",0),("excited",0),("sad",0)]
func increaseStrength(i:Int)->Int {
switch i {
case 0: return 1
case 1: return 2
case 2: return 3
case 3: return 0
default :return 0
}
}
#IBAction func HappyBA(sender: AnyObject) {
for emo in emotions {
if (emo.type == "happy" ){
emo = (type:emo.type,strength:increaseStrength(emo.strength))
}
}
println(emotions)
}
If there are better way to do the assignment please tell me I am so appreciated ! Thanks..
There is no point assigning to emo even if you could do it. This is not the same as replacing the corresponding object in the array - which is what you do want to do. emo is a copy; even if you were to set a property of it, it wouldn't affect the one back in the array. And certainly setting the variable would not magically read back into the array!
Here's one solution. Instead of cycling thru emotions in your for-loop, cycle thru enumerate(emotions). Now you have a tuple of an index number along with an emotion. If this is the right emotion type, write into the array via the index number.
for (ix,emo) in enumerate(emotions) {
if emo.type == "happy" {
emotions[ix] = (type:emo.type,strength:increaseStrength(emo.strength))
}
}
Or you could use map.
emotions = emotions.map {
emo in
if emo.type == "happy" {
return (type:emo.type,strength:increaseStrength(emo.strength))
} else {
return emo
}
}