my issue is that i am unable to get my score label to update properly. I am trying to add +1 when there is a correct selection of an image. However it will only update occasionally which i believe is down to the randomness of the array but i'm not sure. I have tried to change the values or how things are randomised but it wont play ball or effects the desired functionality of the game. I think this is one of those things where i have been staring at it too long. Thanks in advance!
#State private var targetArray = ["Target1", "Target2", "Target3", "Target4", "Target5", "Target6", "Target7", "Target8", "Target9", "Target10"]
#State private var MainTarget = Int.random(in: 0...5)
#State private var numbers = Array(0...5).shuffled()
#State private var score = 0
func buttonAction() {
// randomise the images
targetArray.shuffle()
numbers.shuffle()
self.MainTarget = Int.random(in:
0...self.numbers.count - 1)
// correct target selected
if self.MainTarget == self.numbers[0] {
self.score += 1 }
if self.MainTarget == self.numbers[1] {
self.score += 1 }
if self.MainTarget == self.numbers[2] {
self.score += 1 }
if self.MainTarget == self.numbers[3] {
self.score += 1 }
if self.MainTarget == self.numbers[4] {
self.score += 1 }
if self.MainTarget == self.numbers[5] {
self.score += 1
} // wrong target selected. Add game over
else { self.score -= 1
}
}
Not sure whether I'm getting your question right. But it looks like, as you can simply replace your if-statements with the following code (it doesn't matter which element in the array is equal to MainTarget, because you add 1 to the score variable, regardless of which number matches with MainTarget):
if numbers.contains(self.MainTarget) {
score += 1
} else {
score -= 1
}
The problem with your code is, that you will always decrease your score-variable by 1 execpt for the scenario the last if-statement is true. So if your first condition is true, you add 1 to score, but in the end you will decrease score by 1, because your last if check will fail...
EDIT: There might be even some logical issues, because numbers will always contains MainTarget, since MainTarget is between 0 and 5 and numbers contains all numbers from 0 til 5...
So just incase anyone is interested for the future i have solved the issue by instead of randomising my array ect every time a button is pressed it will now check for the win condition first separately on each button then randomise and update score label.
self.buttonAction()
if self.MainTarget == self.numbers[0] {
self.score += 1 } else { self.score -= 1 }
// randomise the index position and index chosen
if self.MainTarget == self.numbers[0] {
self.numbers.shuffle(); self.MainTarget = Int.random(in: 0...self.numbers.count - 1) }
Related
I am working through hackingwithswift doing the 100 Days of SwiftUI and currently on Day 35 which needs me to build a times table app.
Unfortunately, I have got stuck at a very early stage and feel stupid asking.
How can I make my array index start at 1 rather than 0?
Below is my code and screenshot of the canvas:
struct ContentView: View {
#State private var number = 0
#State private var question = Int.random(in: 0..<13)
let numberRange = Array<Int>(1 ... 12)
var body: some View {
VStack {
Picker("What times tables do you want to test your knowledge on?", selection: $number) {
ForEach(0 ..< numberRange.count) {
Text("\(self.numberRange[$0])")
}
}
.pickerStyle(SegmentedPickerStyle())
Text("What is \(number) x \(question) = ")
}
}
}
From Apple documentation:
The first element of a nonempty array is always at index zero.
Basically you'd need to add +1 to your number variable.
var correctNumber: Int {
number + 1
}
And use this correctNumber when displaying values or performing calculations.
Text("What is \(correctNumber) x \(question)?")
As correctNumber is a computed property it will always be up to date with number variable.
I have working code, that delete row from sheet if column corresponds to one of the conditions. It based on arrays and because of it works much more faster than standard google sheet deleteRow function. I call it like this:
deleteRowsBV('SIZ',4,'0','')
where
deleteRowsBV(listName,ColNum,FirstSearch,SecondSearch)
What I want is a call function with more or less and equal signs, like this:
deleteRowsBV('SIZ',4,<='0',=='')
But in case of my main function, it doesn't work, when I specify a variable instead of a sign and a value.
Here is main function:
function deleteRowsBV(listName,ColNum,FirstSearch,SecondSearch) {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName(listName);
var DataLengBefore = sheet.getLastRow();
var DataColLeng = sheet.getLastColumn();
var data = sheet.getRange(1,1,DataLengBefore,DataColLeng).getValues();
for (var i = data.length-1; i >= 0; i--) {
if (data[i][ColNum] <= FirstSearch||data[i][ColNum] == SecondSearch) {
data.splice(i, 1);
}
}
sheet.getRange(10, 1, DataLengBefore,DataColLeng).clearContent();
sheet.getRange(10, 1,data.length,5).setValues(data);
}
Based from this related post, spreadsheet rows and columns are numbered starting at 1, for all methods in the SpreadsheetApp, while javascript arrays start numbering from 0. You need to adjust between those numeric bases when working with both. When deleting rows, the size of the spreadsheet dataRange will get smaller; you did take that into account, but because you're looping up to the maximum size, the code is complicated by this requirement. You can simplify things by looping down from the maximum.
You may refer with this thread. However, this only looks at the value from a single cell edit now and not the values in the whole sheet.
function onEdit(e) {
//Logger.log(JSON.stringify(e));
//{"source":{},"range":{"rowStart":1,"rowEnd":1,"columnEnd":1,"columnStart":1},"value":"1","user":{"email":"","nickname":""},"authMode":{}}
try {
var ss = e.source; // Just pull the spreadsheet object from the one already being passed to onEdit
var s = ss.getActiveSheet();
// Conditions are by sheet and a single cell in a certain column
if (s.getName() == 'Sheet1' && // change to your own
e.range.columnStart == 3 && e.range.columnEnd == 3 && // only look at edits happening in col C which is 3
e.range.rowStart == e.range.rowEnd ) { // only look at single row edits which will equal a single cell
checkCellValue(e);
}
} catch (error) { Logger.log(error); }
};
function checkCellValue(e) {
if ( !e.value || e.value == 0) { // Delete if value is zero or empty
e.source.getActiveSheet().deleteRow(e.range.rowStart);
}
}
I made a Quiz Game in Swift 2 last year, now I need to use it again when I converted it to Swift 3 the answers randomize now... Here is a sample Question Structure...
Questions = [Question(Question: "What is the Biggest Hit of Bing Crosby?" , Answers: ["Swinging on a Star", "Now is the Hour", "White Christmas", "Beautiful Dreamer"], Answer: 2),]
This is where I randomize the questions and put them into the labels
func PickQuestions() {
counter += 1
score += 1
scoreLbl.text = "\(score)"
restartBtn.isEnabled = false
if Questions.count > 0 && counter <= 15 {
QNumber = Int(arc4random_uniform(UInt32(Questions.count)))
QLabel.text = Questions[QNumber].Question
AnswerNumber = Questions[QNumber].Answer
for i in 0..<Buttons.count{
Buttons[i].setTitle(Questions[QNumber].Answers[i], for: UIControlState())
}
Questions.remove(at: QNumber)
}
}
I had to change the following line manually which may have caused an issue from...
QNumber = Int(arc4random_uniform(UInt32(Questions.count)))
to
QNumber = random() % Questions.count
Thanks
Arrays are unordered collections, meaning that their order could potentially change without your knowing. Your best bet would be to create a single array containing a struct that holds both the question and answer, like so:
struct QuizItem {
var question: String!
var answer: String!
var answerOptions: [String]!
init(q: String, a: String, aOptions:[String]) {
self.question = q
self.answer = a
}
}
Change your declaration to look like the following:
let items = [QuizItem(...)]
Your code like this:
func PickQuestions() {
counter += 1
score += 1
scoreLbl.text = "\(score)"
restartBtn.isEnabled = false
if items.count > 0 && counter <= 15 {
QNumber = Int(arc4random_uniform(UInt32(Questions.count)))
let item = items[QNumber]
QLabel.text = item.question
for i in 0..<Buttons.count{
Buttons[i].setTitle(item.answerOptions[i], for: UIControlState())
}
items.remove(at: QNumber)
}
}
Also, kind of picky but worth highlighting still. Swift is a camel case language and although this rule isn't set in stone, you should try and stick to the widely recognised coding practices.
I'm working on Xcode 8 and Swift 3.
So far I have connected a button with a label. The label is set at 0 and by clicking it, it will change the number by 1.
Now what I'm trying to do is I want to set an array of images to be displayed after clicking it.
So image 1 shown at 0 then image 2 shown once the button is clicked 1-10 times,
then image 3 shown after button is clicked 20-30 times,
then image 4 is shown after 30-40 clicks/taps of the button.
Also the other images are hidden time the respected number of clicks.
Here's a pseudo code for array of JPEGs:
var arrayOfPictures: [UIImage] = []
arrayOfPictures.append(UIImage(named:"Image1.jpg")!)
arrayOfPictures.append(UIImage(named:"Image2.jpg")!)
arrayOfPictures.append(UIImage(named:"Image3.jpg")!)
Here's a pseudo code for button's method:
var counter: Int = 0
#IBAction func showPicture(sender: AnyObject?) {
counter += 1
if counter == 0 {
arrayOfPictures[0]
}
else if counter >= 1 && counter <= 10 {
arrayOfPictures[1]
}
else if counter >= 11 && counter <= 20 {
arrayOfPictures[2]
}
else if ....................
............................
}
I have been trying to iterate through an array to check how many times two particular values occur. I came up with this code:
var paymentNum = 0
var creditNum = 0
for index in images {
if images.objectAtIndex(index) == 0 {
paymentNum = paymentNum + 1
} else {
creditNum = creditNum + 1
}
}
This doesn't seem to work though. I just get the error 'AnyObject' is not convertible to 'Int'.
Where am I going wrong?
I'm making some pretty huge assumptions because you don't have much detail about what's going on.
I'm assuming that images is an NSArray. NSArray in Objective-C translates into an [AnyObject] in swift.
When you have a for-each style loop like this
for value in array
{}
the loop will iterate through each value in the array. Value is the actual object in the array, not a counter as in a for(int i = 0; i < 10; i++) style loop
So what you're probably really expecting to do is
for item in images {
if item == 0 {
paymentNum++
} else {
creditNum++
}
}
you also might need to cast the loop from an [AnyObject] to an [Int] like this
let tmp = images as [Int]
for item in tmp
{...}
or, cast the value pulled out of the array like this
for item in images {
if (item as Int) == 0 {
paymentNum++
} else {
creditNum++
}
}
But the former is probably preferable
paste ina playground:
import Foundation
let images = [1, 0, 1, 1, 0, 0, 1, 0, 1, 1]
var paymentNum = 0
var creditNum = 0
for item in images {
println(item)
if item == 0 {
paymentNum = paymentNum + 1
} else {
creditNum = creditNum + 1
}
}
println(paymentNum) //4
println(creditNum) //6
There's a more compact way of achieving that, in just 2 lines of code.
It makes the assumption that an array element it's a credit if its value is 1, otherwise is 0.
That said, if you sum up all elements of array, you obtain the number of credits - the number of payments is the array size minus the number of credits.
To sum all elements of the array, the simplest way is using the reduce method (more info here)
var creditNum = images.reduce(0, combine: { $0 + $1 } )
var paymentNum = images.count - creditNum
If using values different than 0 or 1 to identify credits and payments, then the calculation can be modified to check for explicit values as follows:
var creditNum = images.reduce(0, combine: { $0 + ($1 == 1 ? 1 : 0) } )
Here it takes the previous count ($0) and add either 1 or 0, depending whether the element array ($1) is equal to 1 or not.