Swift equivalent of this ActionScript function - ios

I translated this tutorial on BSP into swift. In the tutorial there's this ActionScript function.
public function getRoom():Rectangle
{
// iterate all the way through these leafs to find a room, if one exists.
if (room != null)
return room;
else
{
var lRoom:Rectangle;
var rRoom:Rectangle;
if (leftChild != null)
{
lRoom = leftChild.getRoom();
}
if (rightChild != null)
{
rRoom = rightChild.getRoom();
}
if (lRoom == null && rRoom == null)
return null;
else if (rRoom == null)
return lRoom;
else if (lRoom == null)
return rRoom;
else if (FlxG.random() > .5)
return lRoom;
else
return rRoom;
}
}
I translated this function into Swift (to the best of my ability) I must have written it wrong because the function is returning a nil value when it shouldn't be.
My version in Swift:
// left/right child are initialized as follows:
// leftChild:Room?
// rightChild:Room?
public func getRoom() -> Room? {
if room != nil {
return room
} else {
var lRoom:Room?
var rRoom:Room?
if leftChild != nil {
lRoom = leftChild!.getRoom()!
}
if rightChild != nil {
rRoom = rightChild!.getRoom()!
}
if lRoom == nil && rRoom == nil {
return nil
} else if rRoom == nil {
return lRoom
} else if lRoom == nil {
return rRoom
} else if Double.random(in: 0..<1.0) > 0.5 {
return lRoom
} else {
return rRoom
}
}
}
Where Room is a basic class I made to help me handle the rooms.
class Room {
var x1:Int
var x2:Int
var y1:Int
var y2:Int
var center:CGPoint
init(X: Int, Y: Int, W: Int, H: Int) {
x1 = X
x2 = X + W
y1 = Y
y2 = Y + H
center = CGPoint(x: (x1 + x2) / 2, y: (y1 + y2) / 2)
}
}
I'm getting a nil value when I shouldn't be. I think I translated the function wrong. Rectangle would be CGRect in Swift but I replaced it with my Room class in other places in the code, so I know it'll work with the Room class here.
How would this function be written in Swift?

Your problem is that you are force unwrapping the result of getRoom - This function returns an optional and can legitimately return nil when your traversal hits a leaf node. Force unwrapping nil results in a crash
By using conditional unwrapping correctly you can not only make your code more readable, you can eliminate the crash.
public func getRoom() -> Room? {
if let _ = room {
return room
}
let lRoom = leftChild?.getRoom()
let rRoom = rightChild?.getRoom()
switch (lRoom != nil, rRoom != nil) {
case (false,false):
return nil
case (true,false):
return lRoom
case (false,true):
return rRoom
case (true,true):
return arc4random_uniform(2) == 1 ? lRoom: rRoom
}
}

Related

How to get the row index of 2D Array?

I am new to Swift and I am using a 2D array for comparing and I need to get the row index once the condition is true but I got an error state that cannot invoke index with an argument list of type (of:Array<Float>)
My Code:
var entryCoordinate: [[Float]] = [[130.6,61.0],[167.5,61.0],[204.5,61.0],[243.6,61.0],[281.16,61.0],[315.3,61.0]]
for indexs in entryCoordinate
{
if indexs[0] == startPathPointX && indexs[1] == startPathPointY
{
let pathStartElement = indexs.index(of: indexs)
print(pathStartElement)
}
if indexs[0] == endPathPointX && indexs[1] == endPathPointY
{
let pathEndElement = indexs.index(of: indexs)
print(pathEndElement)
}
}
From your code with startPathPointY and endPathPointY you need to compare the second object from 2D array but you keep comparing the first one and you con use index(where:) with your array like this to get the pathStartElement and pathEndElement.
if let pathStartElement = entryCoordinate.index(where: { $0[0] == startPathPointX && $0[1] == startPathPointY }) {
print(pathStartElement)
}
if let pathEndElement = entryCoordinate.index(where: { $0[0] == endPathPointX && $0[1] == endPathPointY }) {
print(pathEndElement)
}
Try this code:
let myIndexPathStartElement = self.arrImagetData.index(where: { $0[0] == startPathPointX && $0[1] == startPathPointY })
let myIndexPathEndElement = self.arrImagetData.index(where: { $0[0] == endPathPointX && $0[1] == endPathPointY })

How do I check if UIImage is empty in swift?

This is my code but it seems the conditional "if" check for UIImage being empty is not executing. Is it the wrong way of checking if UIImage is empty? I have also tried
if allStyleArrays[i][ii][iii] as UIImage? == nil {
...
}
And not working, please if none of those methods checks, what is the correct way?
Thanks.
Code:
for var i = 0; i <= allStyleArrays.count; i++ {
if i == allStyleArrays.count {
self.performSegueWithIdentifier("toStylistReviewAndConfirm", sender: self)
} else {
for var ii = 0; ii < allStyleArrays[i].count; ii++ {
for var iii = 0; iii < allStyleArrays[i][ii].count; iii++ {
if allStyleArrays[i][ii][iii] as UIImage? == UIImage(named: "") {
} else {
switch i {
case 0:
styleN[0].append(allStyleArrays[i][ii][iii])
//print("style 1 \(style1.count)")
break
case 1:
styleN[1].append(allStyleArrays[i][ii][iii])
//print("style 2 \(style2.count)")
break
default:
styleN[2].append(allStyleArrays[i][ii][iii])
//print("style 3 \(style3.count)")
break
}
}
}
}
}
}
try
if allStyleArrays[i][ii][iii].imageAsset == nil

swift - sort an array of objects by their optional boolean property without force unwrapping

I can sort this array of store objects by their 'flagship' boolean property, but how can I safely unwrap the 'flagship' property first?
let flagshipStores = self.stores.sort {
$0.flagship! && !$1.flagship!
}
let flagshipStores = self.stores.sort {
guard let flagship0 = $0.flagship, let flagship1 = $1.flagship else { return false }
return flagship0 && !flagship1
}
One more approach: turn the Bool? into an Int, then compare the Ints. You get to specify how a nil value compares to non-nil values.
For instance, this sorts nil values before both false and true:
stores.sort { Int($0.flagship ?? -1) < Int($1.flagship ?? -1) }
This sorts nil values after both false and true:
stores.sort { Int($0.flagship ?? 2) < Int($1.flagship ?? 2) }
You can use the same pattern to make nil compare the same as true or the same as false. It's up to you.
Here's another approach.
You can use flatMap which will remove nil objects and unwrap those that are present. Then, the force unwrap will be safe to sort:
let flagshipStores = stores.flatMap({ return $0.flagship ? $0 : nil }).sort {
$0.flagship! && !$1.flagship!
}
This will remove stores with a nil flagship from the array.
How about:
$0.flagship == true && $1.flagship != true
The left side will succeed if the value is not nil and is true, the right side will succeed if the value is either nil or false.
As mr.Fixit pointed out on a comment, the accepted answer doesn't fully work because it doesn't take care of nils. Here is the correct answer with an extra string sample.
SWIFT 4
for a boolean sorting
let flagshipStores = self.stores.sorted(by: {
guard let flagship0 = $0.flagship, let flagship1 = $1.flagship else {
if $0.flagship == nil && $1.flagship == nil || $0.flagship != nil && $1.flagship == nil{
return true
}
else {
return false
}
}
return ($0.flagship == $1.flagship || $0.flagship == true && $1.flagship == false ? true : false)
})
for strings comparison sorting
let stores = self.stores.sorted(by: {
guard let store0 = $0.store, let store1 = $1.store else {
if $0.store == nil && $1.store == nil || $0.store != nil && $1.store == nil{
return true
}
else {
return false
}
}
return ( ($0.store)?.localizedStandardCompare($1.store!) == ComparisonResult.orderedAscending )
})
To filter nil values just use compactMap before sort
let flagshipStores = self.stores.compactMap { return $0.flagship }.sorted {
$0 && !$1
}
You could use this function to compare the Optional values without the need to unwrap.
func sortOptionalValues<T: Comparable>(lhs: T?, rhs: T?) -> Bool? {
switch (lhs != nil, rhs != nil) {
case (false, false):
return nil
case (true, false):
return true
case (false, true):
return false
case (true, true):
guard let lhs = lhs, let rhs = rhs else { return nil }
return lhs < rhs
}
}

Stuck in a loop. Very strange because the code sometimes work and sometimes just freezes

I am writing a puzzle game for an IOS. In my code I need to fill an array with some random (and non-random numbers) that will represent the main data structure.
func Random(r : Range<Int>) -> Int {
return Int(arc4random_uniform(UInt32(r.endIndex - r.startIndex))) + r.startIndex
} // function to generate random number
var arrWithColors = [Int]() // array that will hold the numbers
//function to that check if an array contains a number in a range already
func checkForNumberInArrayWithRange(r: Range <Int>, n: Int ) -> Bool {
for i in r.startIndex..<r.endIndex {
if arrWithColors[i] == n { return true }
}
return false
}
// here is the main function where i keep getting stuck. Out of let's say five times it would only work 3 or even less.
func randHexWithTag() {
var rNumber : Int = Random(0...5)
for i in 0...5 {
while (true) {
rNumber = Random(0...5)
if !checkForNumberInArrayWithRange(0...5, n: rNumber) {
break
}
}
arrWithColors[i] = rNumber
}
arrWithColors[10] = arrWithColors[1]
for i in 6...11 {
while(true) {
rNumber = Random(0...5)
if ((rNumber == arrWithColors[0] && i == 9) || (rNumber == arrWithColors[2] && i == 11)) {
continue
}
if !checkForNumberInArrayWithRange(6...11, n: rNumber) {
break
}
}
if (i != 10) {
arrWithColors[i] = rNumber
}
}
arrWithColors[13] = arrWithColors[4]
for i in 12...17 {
while(true) {
rNumber = Random(0...5)
if (rNumber == arrWithColors[3] && i == 12) || (rNumber == arrWithColors[5] && i == 14) {
continue
}
if !checkForNumberInArrayWithRange(12...17, n: rNumber) {
break
}
}
if (i != 13) {
arrWithColors[i] = rNumber
}
}
}
The above code will ALWAYS fail during the first call to checkForNumberInArrayWithRange on this line:
if arrWithColors[i] == n { return true }
That is because arrWithColors is empty, and index i is out of range

Swift: Cannot invoke 'init' with an argument list of type '($t3, NSString)'

In the first function I cannot figure out what I am doing wrong. It returns an error in the line,
return compileShader(GLenum(GL_VERTEX_SHADER), ShaderCode) The error is Cannot invoke 'init' with an argument list of type '($t3, NSString)'
class ShaderHelper{
class func compileVertexShader(ShaderCode: NSString) ->GLint{
return compileShader(GLenum(GL_VERTEX_SHADER), ShaderCode)
}
class func compileShader(type: GLenum, shaderCode: NSString) -> GLuint{
var shaderObjectId = glCreateShader(type);
if(shaderObjectId == 0){
if(LoggerConfig.props.On){
println("Could not create new shader!")
}
return 0
}
var shaderStringUTF8 = shaderCode.cStringUsingEncoding(NSUTF8StringEncoding)
var shaderStringLength: GLint = GLint(Int32(shaderCode.length));
glShaderSource(shaderObjectId, 1, &shaderStringUTF8, &shaderStringLength)
glCompileShader(shaderObjectId)
var compileStatus = GLint()
glGetShaderiv(shaderObjectId, GLenum(GL_COMPILE_STATUS), &compileStatus)
if(compileStatus == 0){
if(LoggerConfig.props.On){
println("Compilation of shader failed.")
}
glDeleteShader(shaderObjectId)
return 0
}else if (compileStatus == 1){
if(LoggerConfig.props.On){
println("Compilation Successful")
}
}
return shaderObjectId;
}
The problem here is not with the init method rather the return type in compileVertexShader and compileShader, while one returns GLInt and other returns GLuint. If you change those to match, your error should be gone.
class ShaderHelper{
class func compileVertexShader(ShaderCode: NSString) ->GLuint{
return compileShader(GLenum(GL_VERTEX_SHADER), shaderCode: ShaderCode)
}
class func compileShader(type: GLenum, shaderCode: NSString) -> GLuint{
var shaderObjectId = glCreateShader(type);
if(shaderObjectId == 0){
if(LoggerConfig.props.On){
println("Could not create new shader!")
}
return 0
}
var shaderStringUTF8 = shaderCode.cStringUsingEncoding(NSUTF8StringEncoding)
var shaderStringLength: GLint = GLint(Int32(shaderCode.length));
glShaderSource(shaderObjectId, 1, &shaderStringUTF8, &shaderStringLength)
glCompileShader(shaderObjectId)
var compileStatus = GLint()
glGetShaderiv(shaderObjectId, GLenum(GL_COMPILE_STATUS), &compileStatus)
if(compileStatus == 0){
if(LoggerConfig.props.On){
println("Compilation of shader failed.")
}
glDeleteShader(shaderObjectId)
return 0
}else if (compileStatus == 1){
if(LoggerConfig.props.On){
println("Compilation Successful")
}
}
return shaderObjectId;
}
The error swift provides much not make sense while debugging. You should be carefully choose parameter type and return type and it should be ok.

Resources