I am trying to update my for loop for Swift 3 and I can't figure it out. I keep getting errors - swift

This is my original function in Swift 2:
// check on winning combinations
func checkWinnerMove(){
for var i = 0; i<winningCombinations.count && !isWinner;i += 1 {
if gameState[winningCombinations[i][0]-1] == activePlayer &&
gameState[winningCombinations[i][1]-1] == activePlayer &&
gameState[winningCombinations[i][2]-1] == activePlayer{
isWinner = true;
}else{
isWinner = false;
}
}
}
I have changed it to this:
// check on winning combinations
func checkWinnerMove(){
for i in 0 ..< winningCombinations.count && !isWinner{
if gameState[winningCombinations[i][0]-1] == activePlayer &&
gameState[winningCombinations[i][1]-1] == activePlayer &&
gameState[winningCombinations[i][2]-1] == activePlayer{
isWinner = true;
}else{
isWinner = false;
}
}
}
But keep getting a error when I add the
&& !isWinner
statment in the for-in loop. The error I get is:
No '..<' candidates produce the expected contextual result type 'Bool'
Any suggestions? Thank You!

Instead of forcibly trying to rewrite your original C-style for loop, consider what you're trying to achieve and attempt to re-write it in "native" Swift from scratch. How about breaking out of your loop once your true condition is met, instead of keeping it in the loop signature? E.g.
for i in 1...5 {
print(i)
if i == 3 { break }
} // 1 2 3
Applied to your example
func checkWinnerMove()
isWinner = false
for i in 0 ..< winningCombinations.count {
if gameState[winningCombinations[i][0]-1] == activePlayer &&
gameState[winningCombinations[i][1]-1] == activePlayer &&
gameState[winningCombinations[i][2]-1] == activePlayer {
isWinner = true
break
}
}
}
The explicit by index access of the (unknown for us) gameState and winningCombinations sequences is quite "unswifty" w.r.t. in the dangers of runtime exceptions for indices out of range for the sequences. So bear in mind that there are safer ways to perform such access.
For future reference, consider reading How to create a Minimal, Complete, and Verifiable example: since we (the potential answerer's of your question) don't have access to/the full information regarding isWinner, winningCombinations, gameState or activePlayer, we can't verify your example. Also, since the question cover a concept, it could be boiled down to a more minimal form. (Welcome to StackOverflow!)

Related

If if statement returns true never execute that function

I've a function with if statement inside it, I want to check everytime person clicks, whenever the if statement returns true, I want that function to be removed or never again called, is it possible to achieve in swift?
func checkLevelUp(){
if CookieViewController.moneyLevel >= 3 && CookieViewController.bonusLevel >= 3 && CookieViewController.spinLevel >= 3 {
print("Level up !!!!!!!") // if this is printed, I never want checkLevelUp function to exists
}
}
You need to store this particular state outside the scope of this function.
var didLevelUp = false
func checkLevelUp() {
guard !didLevelUp else {
return // return out of the function if `didLevelUp` is not false
}
if CookieViewController.moneyLevel >= 3 &&
CookieViewController.bonusLevel >= 3 &&
CookieViewController.spinLevel >= 3 {
print("Level up !!!!!!!")
didLevelUp = true
}
}
How you store it outside the scope of the function is up to you but this is the solution you're looking for.

JS timeout causes eval exception

For some reason, one of my JS files is triggering an unsafe-eval Content Security Policy violation on my site. I thought this odd because there is no eval() anywhere in the file. The error happens on the following line:
setTimeout(callSpecific(), (lengthMF * (number.length + 2)));
The only thing I can see here is the arithmetic on the RHS that sets the timeout value. So, I tried:
setTimeout(callSpecific(), (parseInt(lengthMF) * (parseInt(number.length) + 2)));
Same thing. The variables themselves are not even strings - they are defined as:
var lengthMF = 150;
var number = ""; // yes, this is a string but number.length is not!
Why is this triggering a CSP violation? I have other setTimeout()s on the page and this seems to be the only problematic one. The weird thing is replacing the arithmetic expression temporarily with a constant (e.g. 50) does not cause the issue to go away.
If it's necessary, callSpecific() looks something like this:
function callSpecific() {
if (number == 0) {
operatorRing();
} else if (number.length == 2 && number.charAt(1) == 0) {
playReorder();
} else if (number.length == 3) {
//
} else if (number.length <7 || number.length > 11) {
//
} else if (number.length == 11 && (number.charAt(4) == 1 || number.charAt(4) == 0)) {
//
}
}

Swift 3 enum with associated value AND function comparison

I have this struct that has an enum property as well as a function:
struct UserInput {
enum State {
case unrestricted
case restricted(because: WarningType)
enum WarningType {
case offline
case forbidden
}
}
var config: UserInputConfig?
var state: State = .unrestricted
func isConfigured() -> Bool {
// Arbitrary checks about the config...
}
}
Is there a way to rewrite the following conditionals so that the check for isConfigured() and state are in the same statement?
if case .restricted = userInput.state {
return 1
} else if userInput.isConfigured() {
return 1
} else {
return 0
}
It seems because the State enum uses associated values, you cannot simply write if userInput.state == .restricted || userInput.isConfigured(), you need to use the if case syntax. There must be a way around this?
You would like to do this:
if case .restricted = userInput.state || userInput.isConfigured() {
return 1
} else {
return 0
}
but there is currently no way to do an OR with pattern matching. There are a couple of ways of doing AND.
By using DeMorgan's Laws, you can turn if a || b into if !(!a && !b) and by reversing the then and else clauses of your if statement, you can just check for if !a && !b.
Unfortunately, you can't say if !(case .restricted = userInput.state), but since your enum has only 2 cases, you can replace that with if case .unrestricted = userInput.state.
Now, how do you use that with another statement? You can't use && for the same reason you can't use ||.
You can check for the failing case by using a pattern that matches both failing conditions (which is using AND) and then return 1 if both failing conditions aren't met:
if case (.unrestricted, false) = (userInput.state, userInput.isConfigured()) {
return 0
} else {
return 1
}
Equivalently you can use a multi-clause condition:
if case .unrestricted = userInput.state, !userInput.isConfigured() {
return 0
} else {
return 1
}
In addition to being shorter and IMO easier to read, this second method can short circuit and skip calling userInput.isConfigured in the case where case .unrestricted = userInput.state fails.
You can do it really cleanly with a switch statement, and pattern matching:
switch userInput.state
{
case .unrestricted:
return userInput.isConfigured() ? 1 : 0;
case .restricted(_):
return 1
}

Dictionary String Equivalancy Problems

I am trying to code A* Pathfinding in Swift.
At this point I am encountering a problem in retrieving the G-Costs of my closed list.
This problem is that when I try to search the dictionary for an entry, a nil is returned even though I believe I am entering the right key.
Here is the relevant code (note: Dictionary is in string:Int format as it does not want CGPoints).
print("\(closedList["\(currentPos)"])")
print("\(currentPosString)")
print("\(closedList)")
GCost = GCost + (Int)(closedList["\(currentPosString)"]!)
CurrentPosString is a String, and CurrentPos is a CGPoint (I have tried both).
Here is the read out from this code (I have omitted lots of code).
nil
4, 4
["4.0, 4.0": 0]
(The last line returns an error due to a nil).
My question is how do I make the 'closedList[currentPosString]' have the right format to successfully access the entry and return 0?
Code to generate closedPosString:
closedList["\(currentBest)"] = openList["\(currentBest)"]
openList["\(currentBest)"] = nil
openListOrder["\(currentBest)"] = nil
for i in 0 ..< mapTerrain.numberOfColumns{
for j in 0 ..< mapTerrain.numberOfRows{
if currentBest == "\(i), \(j)"{
currentPos = CGPoint(x: i, y: j)
currentPosString = "\(i), \(j)"
closedList["\(currentPos)"] = closedList[currentBest!]
print("\(closedList["\(currentPos)"])")
print("a") //not printing for some reason
foundNextNewPos = true
}
if foundNextNewPos == true{
break
}
}
if foundNextNewPos == true{
break
}
}
Tried a rebuilt with this code, it still broke:
currentPosString = currentBest!
currentBest = nil
Generation of currentBest:
for key in openList.keys{
let tester = openList["\(key)"] //find way to not get a nil later
//print("\(openList["\(currentBest)"]!)") //gives nil
if key == "\(endPoint)"{
currentBest = key
foundEnd = true
break
}else if openList["\(currentBest)"] == nil{
currentBest = key
}else if tester! < openList["\(currentBest)"]!{
currentBest = key
} else if tester == openList["\(currentBest)"]{
if openListOrder["\(key)"]! > openListOrder["\(currentBest)"]!{
currentBest = key
}
}
}
The problem is that there is no entry "4, 4", the entry "4.0, 4.0" comes from an earlier line of code that relied on CGFloats to make the key, editing this to use the same format ("Int, Int") made it work.
if hexCounter < 3 && openList["\(currentPos.x), \(currentPos.y)"] == nil{
closedList["\(currentPos.x), \(currentPos.y)"] = 0
}
to
if hexCounter < 3 && openList["\(currentPosString)"] == nil{
closedList["\(currentPosString)"] = 0
}

Swift on array.sort - Expression was too complex to be solved in reasonable time; consider breaking up the expression into distinct sub-expressions

I am downgrading Swift code from Xcode 8.3.1 to Xcode 7.3.1.
The Swift compiler of Xcode 7.3.1 raises
Expression was too complex to be solved in reasonable time; consider breaking up the expression into distinct sub-expressions
while pointing on line zeroParameterAndPaths.sort {. The code was ok in Xcode 8.3.1.
What's wrong and how to fix it?
class NewConnectingSegmentZeroParameterAndPath {
let step : Int; // 0 = main, 1 = first outline, 2 = second outline
let parameter : CGFloat;
init(step: Int, parameter: CGFloat) {
self.step = step;
self.parameter = parameter;
}
}
var zeroParameterAndPaths : [NewConnectingSegmentZeroParameterAndPath] = [];
// ... some zeroParameterAndPaths .appendContentsOf calls
zeroParameterAndPaths.sort {
return $0.parameter < $1.parameter
|| ($0.parameter == $1.parameter
&& ($0.step == 1 || ($0.step == 0 && $1.step == 2))
)
};
You have two choices. One is simply to do what the error message suggests, i.e. pulling the complex bool apart into separate pieces:
zeroParameterAndPaths.sort {
let bless = ($0.parameter < $1.parameter)
let beq = ($0.parameter == $1.parameter)
let band = ($0.step == 0 && $1.step == 2)
let bor = ($0.step == 1 || band)
let beqandbor = (beq && bor)
return (bless || beqandbor)
};
The other is to provide an explicit in line giving the param types and result type:
zeroParameterAndPaths.sort {
(a:NewConnectingSegmentZeroParameterAndPath, b:NewConnectingSegmentZeroParameterAndPath) -> Bool in
return a.parameter < b.parameter
|| (a.parameter == b.parameter
&& (a.step == 1 || (a.step == 0 && b.step == 2))
)
};
You could also make your class a little bit more helpful and make it implement the condition. The compiler is much less likely to get confused in a function body than in a closure:
class NewConnectingSegmentZeroParameterAndPath {
let step : Int; // 0 = main, 1 = first outline, 2 = second outline
let parameter : CGFloat;
init(step: Int, parameter: CGFloat) {
self.step = step;
self.parameter = parameter;
}
func orderedBefore(_ other: NewConnectingSegmentZeroParameterAndPath) -> Bool
{
return parameter < other.parameter
|| parameter == other.parameter
&& (step == 1 || step == 0 && other.step == 2)
}
}
var zeroParameterAndPaths : [NewConnectingSegmentZeroParameterAndPath] = [];
// ... some zeroParameterAndPaths .appendContentsOf calls
zeroParameterAndPaths.sort { $0.orderedBefore($1) }
Apart from the issue of the type inference engine not being able to quickly resolve such complex bool expressions, such expressions are really hard to follow. I suggest you break it down into something simpler, like so:
zeroParameterAndPaths.sort {
if $0.parameter != $1.parameter { return $0.parameter < $1.parameter ]
if $0.step == 1 { return true }
if $0.step == 0 && $1.step == 2 { return true }
return false
};
There's my attempt at it. I'm not even sure if it's correct, the original expression is pretty hard to follow.