How to break up expressions involve bitwise shift operators? Swift - ios
The code below is generating an error and fails to run as the expression was too 'complex'.
for row in 0...NumRows {
for column in 0...NumColumns {
let topLeft = (column > 0) && (row < NumRows)
&& level.tileAt(column: column - 1, row: row) != nil
let bottomLeft = (column > 0) && (row > 0)
&& level.tileAt(column: column - 1, row: row - 1) != nil
let topRight = (column < NumColumns) && (row < NumRows)
&& level.tileAt(column: column, row: row) != nil
let bottomRight = (column < NumColumns) && (row > 0)
&& level.tileAt(column: column, row: row - 1) != nil
let value = Int(topLeft.hashValue) | Int(topRight.hashValue) << 1 | Int(bottomLeft.hashValue) << 2 | Int(bottomRight.hashValue) << 3
if value != 0 && value != 6 && value != 9 {
let name = String(format: "Tile_%ld", value)
let tileNode = SKSpriteNode(imageNamed: name)
tileNode.size = CGSize(width: TileWidth, height: TileHeight)
var point = pointFor(column: column, row: row)
point.x -= TileWidth/2
point.y -= TileHeight/2
tileNode.position = point
tilesLayer.addChild(tileNode)
}
}
}
Specifically this line:
let value = Int(topLeft.hashValue) | Int(topRight.hashValue) << 1 | Int(bottomLeft.hashValue) << 2 | Int(bottomRight.hashValue) << 3
The error is as follows:
Expression was too complex to be solved in reasonable time; consider breaking up the expression into distinct sub-expressions
How would you break up the expression for value in such a way that the code following it keeps the same answer?
hashValue is already an Int, so the Int(...) constructors are not
needed. This compiles in Xcode 9:
let value = topLeft.hashValue | (topRight.hashValue << 1) | (bottomLeft.hashValue << 2) | (bottomRight.hashValue << 3)
But that is a bad idea! It relies on the hash value of booleans having specific values:
false.hashValue == 0
true.hashValue == 1
which is nowhere guaranteed. (The only guarantee is that identical elements have the same hash value. One must not even assume that hash
values are equal across different executions of your program,
see Hashable).
A better solution would be
let value = (topLeft ? 1 : 0) + (topRight ? 2 : 0) + (bottomLeft ? 4 : 0) + (bottomRight ? 8 : 0)
Alternatively, use a switch-statement. Example:
switch (topLeft, topRight, bottomLeft, bottomRight) {
case (false, false, false, false):
// ... all false ...
case (false, true, true, false):
// ... topRight and bottomLeft are true ...
case (true, false, false, true):
// ... topLeft and bottomRight are true ...
default:
// ... all other cases ...
}
Related
Hackerrank New Year Chaos Swift
I am trying to solve Hackerrank's New Year Chaos problem in Swift. https://www.hackerrank.com/challenges/new-year-chaos/problem It is about finding the number of bribes people made on a line waiting for a roller coaster ride. For example, there is a total of 3 bribes in this list [2, 1, 5, 3, 4]. Person 2 bribed person 1. Person 5 bribed person 3 and 4. If there are more than 2 bribes by a person, the line becomes "Too chaotic". I was able to get an exponential solution. However, I want to make it linear. func minimumBribes(q: [Int]) -> Void { var bribeCount = 0 var chaotic = false // for i in 0..<q.count { // if q[i] - (i + 1) > 2 { // chaotic = true // break // } // // for j in i + 1..<q.count { // if q[i] > q[j] { // bribeCount += 1 // } // } // } var i = 0 while i < q.count - 1 { if q[i] - (i + 1) > 2 { chaotic = true break } else if q[i] > i + 1 { bribeCount += (q[i] - (i + 1)) i += 1 } else if q[i] <= i + 1 && q[i] > q[i + 1] && q.indices.contains(i + 1) { bribeCount += 1 i += 1 } else { // q[i] < q[i + 1] i += 1 } } if chaotic { print("Too chaotic") } else { print(bribeCount) } } I commented out the exponential solution, which works. But the linear solution does not work and I cannot find out why. It works with the following arrays, [3,2,1,6,5,4], [2,5,1,3,4], [1,2,5,3,7,8,6,4], [1,3,4,2,7,6,5,9,8,11,10,14,13,12]. But there is a really long array in one of the test cases of the problem, which I do not get the correct answer with my linear solution. For this long array, I get 966 with my exponential solution but the linear solution prints 905. [2,1,5,6,3,4,9,8,11,7,10,14,13,12,17,16,15,19,18,22,20,24,23,21,27,28,25,26,30,29,33,32,31,35,36,34,39,38,37,42,40,44,41,43,47,46,48,45,50,52,49,51,54,56,55,53,59,58,57,61,63,60,65,64,67,68,62,69,66,72,70,74,73,71,77,75,79,78,81,82,80,76,85,84,83,86,89,90,88,87,92,91,95,94,93,98,97,100,96,102,99,104,101,105,103,108,106,109,107,112,111,110,113,116,114,118,119,117,115,122,121,120,124,123,127,125,126,130,129,128,131,133,135,136,132,134,139,140,138,137,143,141,144,146,145,142,148,150,147,149,153,152,155,151,157,154,158,159,156,161,160,164,165,163,167,166,162,170,171,172,168,169,175,173,174,177,176,180,181,178,179,183,182,184,187,188,185,190,189,186,191,194,192,196,197,195,199,193,198,202,200,204,205,203,207,206,201,210,209,211,208,214,215,216,212,218,217,220,213,222,219,224,221,223,227,226,225,230,231,229,228,234,235,233,237,232,239,236,241,238,240,243,242,246,245,248,249,250,247,244,253,252,251,256,255,258,254,257,259,261,262,263,265,264,260,268,266,267,271,270,273,269,274,272,275,278,276,279,277,282,283,280,281,286,284,288,287,290,289,285,293,291,292,296,294,298,297,299,295,302,301,304,303,306,300,305,309,308,307,312,311,314,315,313,310,316,319,318,321,320,317,324,325,322,323,328,327,330,326,332,331,329,335,334,333,336,338,337,341,340,339,344,343,342,347,345,349,346,351,350,348,353,355,352,357,358,354,356,359,361,360,364,362,366,365,363,368,370,367,371,372,369,374,373,376,375,378,379,377,382,381,383,380,386,387,384,385,390,388,392,391,389,393,396,397,394,398,395,401,400,403,402,399,405,407,406,409,408,411,410,404,413,412,415,417,416,414,420,419,422,421,418,424,426,423,425,428,427,431,430,429,434,435,436,437,432,433,440,438,439,443,441,445,442,447,444,448,446,449,452,451,450,455,453,454,457,456,460,459,458,463,462,464,461,467,465,466,470,469,472,468,474,471,475,473,477,476,480,479,478,483,482,485,481,487,484,489,490,491,488,492,486,494,495,496,498,493,500,499,497,502,504,501,503,507,506,505,509,511,508,513,510,512,514,516,518,519,515,521,522,520,524,517,523,525,526,529,527,531,528,533,532,534,530,537,536,539,535,541,538,540,543,544,542,547,548,545,549,546,552,550,551,554,553,557,555,556,560,559,558,563,562,564,561,567,568,566,565,569,572,571,570,575,574,577,576,579,573,580,578,583,581,584,582,587,586,585,590,589,588,593,594,592,595,591,598,599,596,597,602,603,604,605,600,601,608,609,607,611,612,606,610,615,616,614,613,619,618,617,622,620,624,621,626,625,623,628,627,631,630,633,629,635,632,637,636,634,638,640,642,639,641,645,644,647,643,646,650,648,652,653,654,649,651,656,658,657,655,661,659,660,663,664,666,662,668,667,670,665,671,673,669,672,676,677,674,679,675,680,678,681,684,682,686,685,683,689,690,688,687,693,692,691,696,695,698,694,700,701,702,697,704,699,706,703,705,709,707,711,712,710,708,713,716,715,714,718,720,721,719,723,717,722,726,725,724,729,728,727,730,733,732,735,734,736,731,738,737,741,739,740,744,743,742,747,746,745,750,748,752,749,753,751,756,754,758,755,757,761,760,759,764,763,762,767,765,768,766,771,770,769,774,773,776,772,778,777,779,775,781,780,783,784,782,786,788,789,787,790,785,793,791,792,796,795,794,798,797,801,799,803,800,805,802,804,808,806,807,811,809,810,814,812,813,817,816,819,818,815,820,821,823,822,824,826,827,825,828,831,829,830,834,833,836,832,837,839,838,841,835,840,844,842,846,845,843,849,847,851,850,852,848,855,854,853,857,856,858,861,862,860,859,863,866,865,864,867,870,869,868,872,874,875,871,873,877,878,876,880,881,879,884,883,885,882,888,886,890,891,889,893,887,895,892,896,898,894,899,897,902,901,903,905,900,904,908,907,910,909,906,912,911,915,913,916,918,914,919,921,917,923,920,924,922,927,925,929,928,926,932,931,934,930,933,935,937,939,940,938,936,943,944,942,941,947,946,948,945,951,950,949,953,952,956,954,958,957,955,961,962,963,959,964,966,960,965,969,968,971,967,970,974,972,976,973,975,979,977,981,982,978,980,983,986,984,985,989,988,987,990,993,991,995,994,997,992,999,1000,996,998] Please help me figure out what is wrong with my solution. Thanks in advance!!
Here is my solution which passes all the test cases :) func minimumBribes(q: [Int]) -> Void { var bCount = 0 var isChaotic = false for (key,value) in q.enumerated() { if (value - 1) - key > 2 { isChaotic = true break } for index in stride(from: max(0, value - 2), to: key, by: 1){ if q[index] > value { bCount += 1 } } } isChaotic ? print("Too chaotic") : print("\(bCount)") }
What you basically need to do is to first check if the element in each loop is on it's correct position. And if not you find out how much further is it from the right position if its greater than 2 you print "Too chaotic". Your solution is correct uptil this point. But if the difference is less than or equal to 2 then you need to increment the bribes and swap the indices to represent updated array. Furthermore if there are two swaps then you need to represent how the array would be effected by these 2 swaps and hence swap these values before the next iteration to ensure the array is in the condition it would be after these swaps. Please refer to my solution below. It passes for all test cases: func swapValues( arr:inout [Int],index:Int, times: Int, bribes:inout Int) -> Bool { if times == 0 { return false } if arr[index] > arr[index+1] { let temp = arr[index+1] arr[index+1] = arr[index] arr[index] = temp bribes = bribes + 1 return swapValues(arr: &arr, index: index+1, times: times-1,bribes: &bribes) }else{ var diff = abs(arr[index+1] - (index+2)) if diff > 2 { print("Too chaotic") return true } var tooChaotic = swapValues(arr: &arr, index: index+1, times: diff,bribes:&bribes) if tooChaotic { return true } return swapValues(arr: &arr, index: index, times: times, bribes: &bribes) } } func minimumBribes(q: [Int]) -> Void { var qC = q var bribes = 0 var i = 0 while i <= qC.count-1{ if i+1 == qC[i] { i = i + 1 continue } let diff = abs(qC[i] - (i+1)) if diff > 2 { print("Too chaotic") return } var tooChaotic = swapValues(arr: &qC, index: i, times: diff, bribes: &bribes) if tooChaotic { return } } print(bribes) }
I found this short and easy solution. func minimumBribes(q: [Int]) -> Void { var ans = 0 var shouldShow = true for i in stride(from: (q.count - 1), through: 0, by: -1) { if (q[i] - (i+1) > 2) { shouldShow = false break; } for j in stride(from: max(0, q[i] - 2), to: i, by: 1){ if q[j] > q[i] { ans += 1 } } } if shouldShow { print(ans) } else { print("Too chaotic") } } https://github.com/AnanthaKrish/example-ios-apps
index out of range array error when removing an element in swift
So I have a platform that spawns a mine and coins on it so first i spawn the mine using a bunch of spawn locations created basd on the size of the screen width and player like so: var spawnLocations:[CGFloat] = [] func getObjectSpawnLocation() { spawnLocations.removeAll() //Create 5 possible spawn locations let numberOfNodes = 5 // Spacing between nodes will change if: 1) number of nodes is changed, 2) screen width is changed, 3) node's size is changed. for i in 0...numberOfNodes - 1 { // spacing used to space out the nodes according to frame (which changes with screen width) (player width go up for closer nodes down for bigger space) var xPosition = (frame.maxX + thePlayer.size.width / 0.57) / CGFloat((numberOfNodes - 1)) * CGFloat(i) //add a half of a player's width because node's anchor point is (0.5, 0.5) by default xPosition += thePlayer.size.width/2 //2 //I have no idea what this does but it works so fuck it. xPosition -= frame.maxX/1 //1.6 spawnLocations.append( xPosition ) } } func spawnMine() { if (theType == LevelType.normal && imageName == "WallObjectFarLeft") { for _ in 0...0 { getObjectSpawnLocation() let obstacle:Object = Object() obstacle.theType = LevelType.normal obstacle.createObject() obstacle.zPosition = 100 addChild(obstacle) let randx = spawnLocations[0] obstacle.position = CGPoint(x: randx, y: 0) spawnLocations.remove(at: 0) createSpecialObject() } } then at the end of the spawn mine function I remove the mines location from the array so it can't be picked again and then I run the create special object function which creates the coin object on the platform like so: func createSpecialObject() { print("\(spawnLocations.count)") for i in 0..<spawnLocations.count { let diceRoll = arc4random_uniform(7) + 1 if (diceRoll <= 2) { let specialObstacle:Object = Object() specialObstacle.theType = LevelType.normal specialObstacle.createSpecialObject() specialObstacle.zPosition = 100 addChild(specialObstacle) var randx = spawnLocations[i] specialObstacle.position = CGPoint(x: randx, y: 0) } } } All this works fine when only removing one of the potential spawn locations from the array but when I try and remove two or even three locations from the array that have more than one mine on a platform and run the game it crashes and gives me a fatal error saying index out of range. What am I doing wrong here and how can I fix this? I remove them like so if there are more than one mine on a platform else if (theType == LevelType.normal && imageName == "WallObjectFarLeft&Middle&FarRight") { for num2 in 0 ..< 3 { getObjectSpawnLocation() let obstacle:Object = Object() obstacle.theType = LevelType.normal obstacle.createObject() obstacle.zPosition = 100 addChild(obstacle) var randx = spawnLocations[0] if num2 == 1 { randx = spawnLocations[2] } if num2 == 2 { randx = spawnLocations[4] } obstacle.position = CGPoint(x: randx, y: 0) } spawnLocations.remove(at: 0) spawnLocations.remove(at: 2) spawnLocations.remove(at: 4) createSpecialObject() }
Here I am giving you example what actually what you'r trying to do in you below code work spawnLocations.remove(at: 0) spawnLocations.remove(at: 2) spawnLocations.remove(at: 4) In your project, your array have four values Index - > 0, 1, 2, 3 Now, you remove object at index : 0, -> spawnLocations.remove(at: 0) So now your updated array have 3 values, index -> 0, 1, 2 In next step, you remove index : 2 -> spawnLocations.remove(at: 2) So updated array will be, index -> 0, 1 Now in the same array you have 2 values at index 0 & 1 and your are tring to remove object at index : 4 -> spawnLocations.remove(at: 4) Hope you get your mistake. Solution Reverse you order of removing array object spawnLocations.remove(at: 4) spawnLocations.remove(at: 2) spawnLocations.remove(at: 0)
init: [0,1,2,3,4] remove at index 0 [1,2,3,4] remove at index 2 [1,2,4] remove at index 4 index out of range You need to shift yours index after each remove init: [0,1,2,3,4] remove at index 0 [1,2,3,4] remove at index 2 - 1 [1,3,4] remove at index 4 - 2 [1,3]
How to make a general method to check for winners in Tic-Tac-Toe
I made a Tic-Tac-Toe game in Ruby. The method below checks for a winner in the vertical columns. How do I make it so that this method can be applied to boards of different sizes, like 4x4, 6x6? def vertical_check(array) result = nil if (array[0][0] == "X" && array[1][0] == "X" && array[2][0] == "X") || (array[0][1] == "X" && array[1][1] == "X" && array[2][1] == "X") || (array[0][2] == "X" && array[1][2] == "X" && array[2][2] == "X") result = "X" elsif (array[0][0] == "O" && array[1][0] == "O" && array[2][0] == "O") || (array[0][1] == "O" && array[1][1] == "O" && array[2][1] == "O") || (array[0][2] == "O" && array[1][2] == "O" && array[2][2] == "O") result = "O" else result = nil end return result end The following is a failed attempt: def vertical_check_x(array) result = nil index = 0 index2 = 0 until result != nil || index == array.length while array[index][index2] == "X" index += 1 end if index == array.length result = "X" else result = nil index = array.length end index2 += 1 end return result end def vertical_check_o(array) result = nil index = 0 index2 = 0 until result != nil || index == array.length while array[index][index2] == "O" index += 1 end if index -1 == array.length result = "O" else result = nil index = array.length end index2 += 1 end return result end def vertical_check(array) result = vertical_check_x(array) if result == nil result = vertical_check_o(array) end return result end
To quickly find a winner in given array, count the number of unique elements, confirm that there is only one unique element and if it is only X or O: def winner arr return arr[0] if arr.uniq.length == 1 && ['X', 'O'].include?(arr[0]) nil end The next problem is selecting the rows, columns and diagonals for an nxn array. Rows are easy: rows = arr.map {|row| row} Columns are as follows - you select elements with the same index for each row: cols = n.times.collect {|i| arr.map {|row| row[i]}} Next are diagonals. There are two diagonals, one starts from leftmost corner and the other from the rightmost. The leftmost diagonal has the sequence as: (0, 0) -> (1, 1) -> (2, 2) .... See the pattern? diag = n.times.collect {|i| arr[i][i]} The rightmost diagonal has pattern that goes like this (for a 3x3): (0, 2) -> (1, 1) -> (2, 0) For a 4x4, it's like this: (0, 3) -> (1, 2) -> (2, 1) -> (3, 0) So, the pattern for an nxn is: (0, n-1-0) -> (1, n-1-1) -> (2, n-1-2) -> ... (i, n-1-i) ... -> (n-1, 0) So: diag = n.times.collect {|i| arr[i][n - 1 - i]} Now, you can just do something like: w = rows.map {|r| winner r}.compact[0] for each array to get the winner.
Optimizing Performance for Level Generation
I'm generating simple game maps using a method described in this post. I'm using the second method of starting with a seed tile and randomly growing out. I'm testing it in a Swift playground on a 30x30 array. The problem is my method takes several minutes to generate a 30x30 map, and maps in my real game might exceed 100x100 tiles. How can I optimize the following code to run faster? import UIKit import SpriteKit var map = [[String]](count: 30, repeatedValue:[String](count: 30, repeatedValue:" ")) var landTiles = [(y: Int,x: Int)]() landTiles.append((15,x: 15)) let minX = 3 let maxX = 28 let minY = 3 let maxY = 28 var coastTiles = [(y: Int,x: Int)]() var hasReachedBounds = false while !hasReachedBounds { coastTiles = [] for tile in landTiles { let coastal = isCoastal(tile.y, x: tile.x) if coastal { coastTiles.append(tile) } } let numTiles = UInt32(coastTiles.count) print(map) let randomTile = coastTiles[Int(arc4random_uniform(numTiles))] if randomTile.x <= minX || randomTile.x >= maxX || randomTile.y <= minY || randomTile.y >= maxY { hasReachedBounds = true break } let coastal = isCoastal(randomTile.y, x: randomTile.x) if !coastal{ continue } let randomPosition = arc4random_uniform(4) + 1 switch randomPosition { case 1: landTiles.append((randomTile.y + 1, randomTile.x)) map [randomTile.y + 1][randomTile.x] = "&" case 2: landTiles.append((randomTile.y, randomTile.x + 1)) map [randomTile.y][randomTile.x + 1] = "&" case 3: landTiles.append((randomTile.y - 1, randomTile.x)) map [randomTile.y - 1][randomTile.x] = "&" case 4: landTiles.append((randomTile.y, randomTile.x - 1)) map [randomTile.y][randomTile.x - 1] = "&" default: break } } func isCoastal (y: Int, x: Int) -> Bool{ if map[y + 1][x] == " " || map[y][x + 1] == " " || map[y - 1][x] == " " || map[y][x - 1] == " "{ return true } else { return false } } print(map)
Is it possible to declare mutable and immutable values/bindings simultaneously?
For example I want to declare let len, (*mutable*) i = if s.Length >= 2 && s.[0] = '0' && (s.[1] = 'x' || s.[1] = 'X') then (s.Length - 2, 2) else (s.Length, 0) constant binding len and mutable i, is it possible ? Added : I will use references then let len, i = if s.Length >= 2 && s.[0] = '0' && (s.[1] = 'x' || s.[1] = 'X') then (s.Length - 2, ref 2) else (s.Length, ref 0)
No. mutable applies to the entire let binding. You'll have to do: let len, i = ... let mutable i = i