I am trying to write this in swift as I could not find any solution written in swift but seem to have hit a roadblock with this implementation.
On the pop and push function, I am not sure if Character is the right return/argument.
class BalancedParam {
struct stack {
var top = -1
var items = [Character]()
mutating func push(_ x: Character) {
items.append(x)
if top == 99 {
print("Stack full")
} else {
top += 1
items[top] = x
}
}
mutating func pop() -> Character {
if top == -1 {
print("Underflow error")
return "0"
} else {
let element = items[top]
top -= 1
return element
}
}
mutating func isEmpty() -> Bool {
return (top == -1) ? true : false
}
}
static func isMatchingPair(_ character1: Character, _ character2: Character) -> Bool {
if character1 == "(" && character2 == ")" {
return true
} else if character1 == "{" && character2 == "}" {
return true
} else if character1 == "[" && character2 == "]" {
return true
} else {
return false
}
}
static func areParenthesisBalanced(_ exp: [Character]) -> Bool {
// Declare an empty character stack
var st = stack()
for i in 0..<exp.count {
if exp[i] == "{" || exp[i] == "(" || exp[i] == "[" {
st.push(exp[i])
}
if exp[i] == "}" || exp[i] == ")" || exp[i] == "]" {
if st.isEmpty() {
return false
} else if !isMatchingPair(st.pop(), exp[i] ) {
return false
}
}
}
if st.isEmpty() {
return true //balanced
} else {
//not balanced
return false
}
}
}
let exp: [Character] = ["{", "(", ")", "}", "[", "]"]
if BalancedParam.areParenthesisBalanced(exp) {
print("Balanced ")
} else {
print("Not Balanced ")
}
I will appreciate any help in understanding what I am doing wrong. Thanks
You can not assign to an empty array, i.e items[top] = x, you can only use this syntax if the array is of size top+1 or larger
So this is not ok
var arr = [Int]()
arr[0] = 1
but this is
var arr = [Int]()
arr.append(0)
arr[0] = 1
Another option since you have a cap on your array size is to init an array of that size and then continue to use the original syntax
var arr = Array(repeating: 0, count: 99)
arr[0] = 1
Related
so i am making game and there is a grid and you can only place if any of the adjacent blocks are a source block, well if you are trying to place a block in the top grid there's no block above it so an Index out of range error will be thrown. I am trying to catch it but xcode seems to think no error is possible. Am i doing this wrong? I guess I could go to each case and add a catch but I feel like this should work.
copy friendly text if you would like to try it out in your own IDE:
func isValidPlacement(row:Int,col:Int) -> Bool {
if let t = try? tiles[row-1][col], t.isSource {
return true
}
else if let t = try? tiles[row][col-1], t.isSource {
return true
}
else if let t = try? tiles[row+1][col], t.isSource {
return true
}
else if let t = try? tiles[row][col+1], t.isSource {
return true
}
else {
return false
}
}
Runtime errors and returning bools is the Objective-C way! Throw throw throw! 🙀
public extension Collection {
/// - Returns: same as subscript, if index is in bounds
/// - Throws: CollectionIndexingError
func element(at index: Index) throws -> Element {
guard indices.contains(index)
else { throw CollectionIndexingError() }
return self[index]
}
}
extension Collection where Element: Collection {
/// - Returns: same as subscripting, if indices are in bounds
/// - Throws: CollectionIndexingError
func element( at indices: (Index, Element.Index) ) throws -> Element.Element {
try element(at: indices.0).element(at: indices.1)
}
}
/// Thrown when `getElement` is called with an invalid index.
public struct CollectionIndexingError: Error { }
extension Tile {
enum PlacementError: Error {
case invalid
case noSources
}
}
extension Collection where
Index == Int,
Element: Collection, Element.Index == Int, Element.Element == Tile
{
func validatePlacement(row: Index, column: Element.Index) throws {
let tiles = [(-1, 0), (0, -1), (1, 0), (0, 1)].compactMap {
try? element( at: (row + $0.0, column + $0.1) )
}
guard !tiles.isEmpty
else { throw Tile.PlacementError.invalid }
guard tiles.contains(where: \.isSource)
else { throw Tile.PlacementError.noSources }
}
}
In Swift. you can only catch instances of Error that are thrown by code, you can't catch runtime exceptions such as an array bounds violation
You can create your own safeAccess function. You don't say what type is in your array so I will use SomeType as an example
func safeAccess(row:Int, col:Int) -> SomeType? {
guard row >= 0, row < tiles.count else {
return nil
}
guard col >= 0, col < tiles[row].count else {
return nil
}
return tiles[row][col]
}
func isValidPlacement(row:Int,col:Int) -> Bool {
if let t = tiles.safeAccess(row:row-1,col:col), t.isSource {
return true
}
if let t = tiles.safeAccess(row:row,col:col-1),, t.isSource {
return true
}
if let t = tiles.safeAccess(row:row+1,col:col), t.isSource {
return true
}
if let t = tiles.safeAccess(row:row,col:col+1), t.isSource {
return true
}
return false
}
You could also define an extension on Array
extension Array {
func element(at index: Int) -> Element? {
if index >= 0 && index < self.count {
return self[index]
}
return nil
}
}
And to use it:
func isValidPlacement(row:Int,col:Int) -> Bool {
if let tiles = tiles.element(at:row-1), let t = tiles.element(at:col), t.isSource {
return true
}
else if tiles.element(at:row), let t = tiles.element(at:col-1), t.isSource {
return true
}
else if let tiles = tiles.element(at:row+1), let t = tiles.element(at:col), t.isSource {
return true
}
else if let tiles = tiles.element(at:row), let t = tiles.element(at:col+1), t.isSource {
return true
}
else {
return false
}
}
Accessing an index of an array which doesn't exist results in a run time exception. You can't use try here because the array is not throwing anything.
Try adding these two lines at the start of the func and get rid of all of try?
guard row <= tiles.count - 1 else {
return false
}
guard col <= tiles[row].count - 1 else {
return false
}
Also i am assuming, whatever the type array stores here is an optional. if not you can remove if lets too
func isValidPlacement(row:Int,col:Int) -> Bool {
guard row <= tiles.count - 1 else {
return false
}
guard col <= tiles[row].count - 1 else {
return false
}
if let t = tiles[row-1][col], t.isSource {
return true
}
else if let t = tiles[row][col-1], t.isSource {
return true
}
else if let t = tiles[row+1][col], t.isSource {
return true
}
else if let t = tiles[row][col+1], t.isSource {
return true
}
else {
return false
}
}
I have following route:
router.post([Page].self, at: "/fetchStatusOfManagedReleases") { (req, pages) -> Future<[Page]> in
let eventIds = pages.map { $0.events }.flatMap { $0 }.map { $0.id }
return Release.query(on: req).filter(\.fbId ~~ eventIds).all().map { releases in
var result: [Page] = []
for p in pages {
let page = p
var pageEvents: [Event] = []
for e in p.events {
let event = e
if let release = releases.first(where: { $0.fbId == e.id }) {
event.inProgress = release.inProgress
event.purpose = release.purpose
_ = try release.testPrices.query(on:req).all().map { testP in
event.testPrices = testP // <--- this line is not applied
}
} else {
event.inProgress = false
}
pageEvents.append(event)
}
page.events = pageEvents
result.append(page)
}
return result
}
}
Unfortunatelly event.testPrices = testP is not applied, it will e not part of the response. What can I do? At some cases I do not need to postpone "return". How can I dissolve scheduling issue?
I do a ~~ operation on TestPrice also as for Release before.
router.post([Page].self, at: "/fetchStatusOfManagedReleases") { (req, pages) -> Future<[Page]> in
let eventIds = pages.map { $0.events }.flatMap { $0 }.map { $0.id }
return Release.query(on: req).filter(\.fbId ~~ eventIds).all().flatMap { releases in
let releaseInnerIds = releases.map {$0.id}
return TestPrice.query(on: req).filter(\.id ~~ releaseInnerIds).all().map { testPrices in
var result: [Page] = []
for p in pages {
let page = p
var pageEvents: [Event] = []
for e in p.events {
let event = e
if let release = releases.first(where: { $0.fbId == e.id }) {
event.inProgress = release.inProgress
event.purpose = release.purpose
event.testPrices = testPrices.compactMap({testPrice in
if testPrice.release.parentID == release.id {
return testPrice
} else {
return nil
}
})
} else {
event.inProgress = false
}
pageEvents.append(event)
}
page.events = pageEvents
result.append(page)
}
return result
}
}
}
I am trying to redevelop the Colony class I wrote for Conway's Game of Life with Sets instead of arrays but am having trouble doing so. Here's what I've got so far:
P.S. I am assuming a fixed Colony size of 20x20.
import Foundation
struct Array2DB {
var values: [Int]
var rows: Int
var cols: Int
init(rows: Int, cols: Int){
self.rows = rows
self.cols = cols
values = [Int](repeating: 0, count: (rows + 2) * (cols + 2) )
}
//allows uasge of the syntax [row, col] for get/set access
subscript(row:Int, col: Int) -> Int {
get {
return values[getIndex(row, col)]
}
set(val) {
values[getIndex(row, col)] = val
}
}
//converts 2D indices to index in data (terminates if out of bounds)
func getIndex(_ row: Int, _ col: Int) -> Int {
assert((row >= -1) && (row <= rows), "row \(row) is out of bounds")
assert((col >= -1) && (col <= cols), "col \(col) is out of bounds")
return (row + 1) * cols + col + 1
}
var description: String {
var desc = "Matrix:\n"
for row in 0 ..< rows {
for col in 0 ..< cols {
desc += " \(values[getIndex(row, col)]) "
}
desc += "\n"
}
return desc
}
}
class Colony: CustomStringConvertible {
let colony: Set = Array2DB[rows, cols, values]
func setCellAlive(xCoor: Int, yCoor: Int) {
colony[xCoor, yCoor] = 1
}
func setCellDead(xCoor:Int, yCoor: Int) {
colony[xCoor, yCoor] = 0
}
func resetColony() {
for i in 0..<colony.rows {
for e in 0..<colony.cols {
colony[i, e] = 0
}
}
}
var description: String {
var desc = ""
for i in 0..<colony.rows {
for e in 0..<colony.cols {
if colony[i, e] == 1 {
desc += "*"
} else {
desc += "-"
}
}
desc += "\n"
}
return desc
}
func isCellALive( xCoor: Int, yCoor: Int) -> Bool{
return colony[xCoor, yCoor] == 1
}
func evolve() {
var colonyUpdate: Array2DB = colony
for i in 0..<colony.rows {
for e in 0..<colony.cols {
let cGen = rules(xCoor: i, yCoor: e)
if ((cGen < 2) || (cGen > 3)) {
colonyUpdate[i, e] = 0
} else if cGen == 3 {
colonyUpdate[i, e] = 1
} else {
if colony[i, e] == 1 {
colonyUpdate[i, e] = 1
} else {
colonyUpdate[i, e] = 0
}
}
}
}
colony = colonyUpdate
}
}
I'm sure that I've implemented it wrong, but how would I turn the arrays to sets? I'm really confused and would appreciate any guidance or feedbac
Your data type Array2DB is not an Array. It is a Struct that contains an array. You can't assign an Array2DB to a variable that you've declared to be of type Set. It won't work.
You also can't use a Set as the storage for Conway's game of life. The Swift Set data type is an unordered collection. It is unsuitable to serve as the storage for the data in the game of life. You want an array, period.
A very little help for you to show an example of using Set in Game of Life.
struct Cell: Hashable {
var x: Int
var y: Int
}
class Colony: CustomStringConvertible {
var aliveCells: Set = Set<Cell>()
let numberOfRows: Int
let numberOfColumns: Int
init(colonySize: Int) {
self.numberOfRows = colonySize
self.numberOfColumns = colonySize
}
func setCellAlive(xCoor: Int, yCoor: Int) {
aliveCells.insert(Cell(x: xCoor, y: yCoor))
}
func setCellDead(xCoor:Int, yCoor: Int) {
aliveCells.remove(Cell(x: xCoor, y: yCoor))
}
func resetColony() {
aliveCells.removeAll(keepingCapacity: true)
}
var description: String {
var desc = ""
for i in 0..<numberOfRows {
for e in 0..<numberOfColumns {
if aliveCells.contains(Cell(x: e, y: i)) { //Usually `x` represents column, and `y` for row
desc += "*"
} else {
desc += "-"
}
}
desc += "\n"
}
return desc
}
//Implement other methods you need
//...
}
As already noted, Set is not a good data type for Game of Life. But you can implement it using Set. Good luck.
I am trying to create a recursive Swift implementation for the solution of the classic puzzle: "How can we distribute n queens on a chess grid of n × n so that no queen can threaten another".
With existing code I encountered the following problems:
Code does not produce all the solutions for n<=8
Code does not product ANY solution for n>=9
Can't seem to compare solutions for n=8 (8x8) and larger because I compute the hash for each Solution class (board) by shifting bits which represent existence of queen or empty tile:
public override var hash: Int {
var hash = 0
for i in 0...self.board.count-1 {
for j in 0...self.board.count-1 {
if self.board[i][j].state == .Queen {
hash |= 1
hash <<= 1
} else {
hash <<= 1
}
}
}
return hash
}
when board is >8x8 value gets corrupted as it is larger than 64 bits (swift Int is Int64). What's a good solution for that?
My current code:
import UIKit
public typealias Board = Array<Array<Cell>>
#objc protocol QueenPlacementDelegate : class {
func solutionsFound(numOfSolutions : Int)
}
class QueenPlacement: NSObject {
var boardView : TTTBoardView?
var boardSize : Int = 0
var solutions : Set<Solution>?
weak var delegate : QueenPlacementDelegate?
private var startCondX : Int = 0
private var startCondY : Int = 0
func start() {
if boardSize == 0 {
print("Board size was not initialized")
return
}
self.solutions = Set<Solution>()
var done = false
self.startCondX = 0; self.startCondY = 0;
while (!done) {
let solution = Solution(boardSize: self.boardSize)
let board = solution.board
self.placeQueen(startCondX, yLoc: startCondY, board: board)
let solutionBoard = self.findSolutionForBoard(board)
if self.numOfQueensOnBoard(solutionBoard) == self.boardSize {
print("solution found")
solution.board = solutionBoard
self.solutions!.insert(solution)
}
done = self.advanceStartConditionsAndCheckIfDone()
if (done) {
if self.solutions!.count > 0 {
self.delegate!.solutionsFound(self.solutions!.count)
}
}
}
}
func advanceStartConditionsAndCheckIfDone() -> Bool {
startCondX++
if startCondX >= self.boardSize {
startCondX = 0
startCondY++
if startCondY >= self.boardSize {
return true
}
}
return false
}
func placeQueen(xLoc : Int, yLoc : Int, board : Board) {
board[xLoc][yLoc].state = .Queen
}
func findSolutionForBoard(board : Board) -> Board
{
let queensPlaced = self.numOfQueensOnBoard(board)
if queensPlaced == self.boardSize {
return board
}
else
{
for i in 0...self.boardSize-1 {
for j in 0...self.boardSize-1 {
if self.canPlaceQueen(xLoc: i, yLoc: j, board: board) {
self.placeQueen(i, yLoc: j, board: board)
}
}
}
let newQueensPlaced = self.numOfQueensOnBoard(board)
// recursion exit conditions: could not place any new queen
if newQueensPlaced > queensPlaced {
self.findSolutionForBoard(board)
} else {
return board
}
}
return board
}
func numOfQueensOnBoard(board : Board) -> Int {
var queensPlaced = 0
for i in 0...self.boardSize-1 {
for j in 0...self.boardSize-1 {
if board[i][j].state == .Queen {
queensPlaced++
}
}
}
return queensPlaced
}
func canPlaceQueen(xLoc xLoc : Int, yLoc : Int, board: Board) -> Bool {
for i in 0...self.boardSize-1 {
if board[i][yLoc].state == .Queen {
return false;
}
if board[xLoc][i].state == .Queen {
return false;
}
}
var x : Int
var y : Int
x = xLoc; y = yLoc;
while ++x < self.boardSize && ++y < self.boardSize {
if board[x][y].state == .Queen {
return false
}
}
x = xLoc; y = yLoc;
while --x >= 0 && ++y < self.boardSize {
if board[x][y].state == .Queen {
return false
}
}
x = xLoc; y = yLoc;
while ++x < self.boardSize && --y >= 0 {
if board[x][y].state == .Queen {
return false
}
}
x = xLoc; y = yLoc;
while --x >= 0 && --y >= 0 {
if board[x][y].state == .Queen {
return false
}
}
return true
}
// singleton!
static let sharedInstance = QueenPlacement()
private override init() {}
}
What is wrong here?
P.S.
for easier reading - full code repo can be found here
It's not an answer in a way that I don't know what is the problem with your version, but here is another one (looks working as I tested it), a little bit simplier (based on Scala By Example - The N-Queens Problem).
func queens(n: Int) -> [[Int]] {
guard n > 3 else {
return [[Int]]()
}
func placeQueens(k: Int) -> [[Int]] {
guard k > 0 else {
return [[-1]] //stupid hack to let the app go to the for-loop in the * marked place
}
var res = [[Int]]()
for var q in placeQueens(k - 1) { //* marked place
if let first = q.first where first == -1 { //this is for removing the hacky -1
q.removeAll()
}
for column in 1...n {
if isSafe(column, queens: q) {
var solution = q
solution.append(column)
res.append(solution)
}
}
}
return res
}
return placeQueens(n)
}
func isSafe(column: Int, queens: [Int]) -> Bool {
for (index, q) in queens.enumerate() {
let dy = (index + 1) - (queens.count + 1)
let dx = q - column
let isDiagonal = dy * dy == dx * dx
if q == column || isDiagonal {
return false
}
}
return true
}
And if you want to draw the solutions out:
func drawTable(table: [Int]) -> String {
var res = ""
table.forEach {
for column in 1...table.count {
if $0 == column {
res += "X "
} else {
res += ". "
}
}
res += "\n"
}
return res
}
And
queens(4).forEach {
print(drawTable($0))
}
Computing the 73712 solutions of n = 13 took some minutes, above that you would probably run out of memory this way.
I need capital letters from a string. With NSString it was sth like:
for (var i = 0; i<str.length; i++) {
let c = str.characterAtIndex(i)
if c >= 'A' && c < 'Z' {
//..
}
}
In Swift it starts like:
for (var i = 0; i<countElements(str); i++) {
//..
}
But I do not know i.e. how to pick i-th character, I am checking this
Here's a slightly more idiomatic version in swift
func capitalLetters(s: String) -> [Character] {
return filter(s) { ("A"..."Z").contains($0) }
}
capitalLetters("fOo BAr") // ["O", "B", "A"]
or even:
func capitalLetters(s: String) -> [Character] {
func isCapital(c: Character) -> Bool {
return ("A"..."Z").contains(c)
}
return filter(s, isCapital)
}
capitalLetters("fOo BAr")
or also, you could make the syntax nicer by providing an extension
extension String {
func capitalLetters() -> [Character] {
func isCapital(c: Character) -> Bool {
return ("A"..."Z").contains(c)
}
return filter(self, isCapital)
}
}
"fOo BAr".capitalLetters()
For example this work fine in Swift :
var st = "Hello World"
for ch in st {
if ch >= "A" && ch <= "Z"{
println(ch)
}
}
And print
H
W
Or you could this instead :
var range = "A"..."Z"
for ch in st {
if range.contains(String(ch)) {
println(ch)
}
}
Or the solution of #Gabrielle updated to Swift 2.0:
func capitalLetters(s: String) -> [Character] {
return s.characters.filter { ("A"..."Z").contains($0) }
}
capitalLetters("fOo BAr") // ["O", "B", "A"]