0

(I'm pretty new to this, so tips on the general form of this post and my code are greatly appreciated!)


I've been playing around with Swift in the IBM Sandbox, and I can't seem to get around the following problem:

func fillPossibilityMatrix() {        //it's a 9x9 Matrix
for i in 0...80 {
    let row = (i - (i % 9)) / 9       //-> row is Valid for 0 - 8
    let column = i % 9                            
    if possibilityMatrix[row, column] == [0] {
        possibilityMatrix[row, column] = possibilities(row, column: column)
    }
}

This gives me 132 unkown error!

  • Even though I can call possibilityMatrix and possibilities() with every combination of values used here, as soon as I put "=" in between them, things get weird.

  • I've seen the 132 error before, when I tried to assign Values to invalid indexes of Arrays/Matrixes, but I don't see that here...

- The following works perfectly fine. (Note the "prints" instead of the "=")

func fillPossibilityMatrix() { for i in 0...80 { let row = (i - (i % 9)) / 9 let column = i % 9 if possibilityMatrix[row, column] == [0] { print(possibilityMatrix[row, column]) print(possibilities(row, column: column)) } } }

  • It also works, when I put different Ranges for the Loop. But it's neither certain values being used nor the size of the Range, that determines whether it does or not.

Whats wrong here? Am I just being stupid? Is this specific to the IBM site?


The Rest

(I'm trying to let it solve Sudoku)

-

possibilityMatrix comes about like this: (here: field <-> possibilityMatrix)

struct Matrix {
    let rows: Int, columns: Int
    var grid: [[Int]]
    init(rows: Int, columns: Int) {
        self.rows = rows
        self.columns = columns
        grid = Array(count: rows * columns, repeatedValue: [0])
    }
   func indexIsValidForRow(row: Int, column: Int) -> Bool {
        return row >= 0 && row < rows && column >= 0 && column < columns
    }
    subscript(row: Int, column: Int) -> [Int] {
        get {
            assert(indexIsValidForRow(row, column: column), "Index out of range")
            return grid[(row * columns) + column]
        }
        set {
            assert(indexIsValidForRow(row, column: column), "Index out of range")
            grid[(row * columns) + column] = newValue
        }
    }
}
var inputArray = [Int!] ()
var input = "003020600900305001001806400008102900700000008006708200002609500800203009005010300"
var field = Matrix(rows: 9, columns: 9)

for char in input.characters {
    inputArray.append(Int(String(char)))
}
func fromInputToField() {
    for i in 0..<inputArray.count {
        let row = (i - (i % 9))/9
        let column = i % 9
        field[row, column][0] = (inputArray[i])
    }
}
fromInputToField()

var possibilityMatrix = field

-

possibilities() and it's sub functions look like this:

func possibilities(row: Int, column: Int) -> [Int] {
    let numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9]
    return numbers.filter {
        !rowContains(row, number: $0) && !columnContains(column, number: $0) && !boxContains(row, c: column, number: $0)
    }
}


func rowContains(r: Int, number: Int) -> Bool {
    for i in 0...8 {
        if possibilityMatrix[r, i][0] == number {
            return true
        }
    }
    return false
}
func columnContains(c: Int, number: Int) -> Bool {
   for i in 0...8 {
        if possibilityMatrix[i, c][0] == number {
            return true
        }
    }
    return false
}
func boxContains (r: Int, c: Int, number: Int) -> Bool {
    let boxLocation = locateBox(r, c: c)
    for x in 0...2 {
        for y in 0...2 {
            if possibilityMatrix[boxLocation.0 + y, boxLocation.1 + x][0] == number {
                return true
            }
        }
    }
    return false
}

func locateBox (r: Int, c: Int) -> (upBorder: Int, leftBorder: Int) {
    if r % 3 != 0 {
        return locateBox(r - 1, c: c)
    }
    if c % 3 != 0 {
        return locateBox(r, c: c - 1)
    }
    return (r, c)
}



for copy-pasting

struct Matrix {
    let rows: Int, columns: Int
    var grid: [[Int]]
    init(rows: Int, columns: Int) {
        self.rows = rows
        self.columns = columns
        grid = Array(count: rows * columns, repeatedValue: [0])
    }
   func indexIsValidForRow(row: Int, column: Int) -> Bool {
        return row >= 0 && row < rows && column >= 0 && column < columns
    }
    subscript(row: Int, column: Int) -> [Int] {
        get {
            assert(indexIsValidForRow(row, column: column), "Index out of range")
            return grid[(row * columns) + column]
        }
        set {
            assert(indexIsValidForRow(row, column: column), "Index out of range")
            grid[(row * columns) + column] = newValue
        }
    }
}
var inputArray = [Int!] ()
var input = "003020600900305001001806400008102900700000008006708200002609500800203009005010300"
var field = Matrix(rows: 9, columns: 9)

for char in input.characters {
    inputArray.append(Int(String(char)))
}
func fromInputToField() {
    for i in 0..<inputArray.count {
        let row = (i - (i % 9))/9
        let column = i % 9
        field[row, column][0] = (inputArray[i])
    }
}
fromInputToField()

var possibilityMatrix = field
func possibilities(row: Int, column: Int) -> [Int] {
    let numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9]
    return numbers.filter {
        !rowContains(row, number: $0) && !columnContains(column, number: $0) && !boxContains(row, c: column, number: $0)
    }
}


func rowContains(r: Int, number: Int) -> Bool {
    for i in 0...8 {
        if possibilityMatrix[r, i][0] == number {
            return true
        }
    }
    return false
}
func columnContains(c: Int, number: Int) -> Bool {
   for i in 0...8 {
        if possibilityMatrix[i, c][0] == number {
            return true
        }
    }
    return false
}
func boxContains (r: Int, c: Int, number: Int) -> Bool {
    let boxLocation = locateBox(r, c: c)
    for x in 0...2 {
        for y in 0...2 {
            if possibilityMatrix[boxLocation.0 + y, boxLocation.1 + x][0] == number {
                return true
            }
        }
    }
    return false
}

func locateBox (r: Int, c: Int) -> (upBorder: Int, leftBorder: Int) {
    if r % 3 != 0 {
        return locateBox(r - 1, c: c)
    }
    if c % 3 != 0 {
        return locateBox(r, c: c - 1)
    }
    return (r, c)
}
func fillPossibilityMatrix() {        //it's a 9x9 Matrix
    for i in 0...80 {
        let row = (i - (i % 9)) / 9       //-> row is Valid for 0 - 8
        let column = i % 9                            
        if possibilityMatrix[row, column] == [0] {
            possibilityMatrix[row, column] = possibilities(row, column: column)
        }
    }
}
fillPossibilityMatrix()
TheSoundDefense
  • 6,753
  • 1
  • 30
  • 42
simsula
  • 147
  • 7
  • Can you show the declarations for `possibilityMatrix` and `possibilities`? – Nate Cook Dec 15 '15 at 00:57
  • Your "for copy-pasting" code generates an error: "Array index out of range" (in a Playground and once compiled with open-source Swift). I think this is what 132 means. – Eric Aya Dec 16 '15 at 12:19
  • @Eric D. But as I've just added in the post: if instead of assigning possibilities() to possibilityMatrix in the last function fillPossibilityMatrix(), you just print them it works perfectly fine. How do you make sense of that? Which Array? – simsula Dec 16 '15 at 23:17
  • We just took a look at error 132 on the backend, and that is indeed an `Index out of range` error you're getting. Our next update to the Sandbox should give a better error message. – TheSoundDefense Dec 18 '15 at 21:14
  • @TheSoundDefense You're a developer of the sandbox? That's so cool! – simsula Dec 18 '15 at 21:40
  • Thanks! :D Anyhow I figured out the issue. I'm writing up an answer now. – TheSoundDefense Dec 19 '15 at 01:53

1 Answers1

1

So it turns out the problem is a pretty simple one. Here are your possibility functions:

func rowContains(r: Int, number: Int) -> Bool {
    for i in 0...8 {
        if possibilityMatrix[r, i][0] == number {
            return true
        }
    }
    return false
}
func columnContains(c: Int, number: Int) -> Bool {
   for i in 0...8 {
        if possibilityMatrix[i, c][0] == number {
            return true
        }
    }
    return false
}
func boxContains (r: Int, c: Int, number: Int) -> Bool {
    let boxLocation = locateBox(r, c: c)
    for x in 0...2 {
        for y in 0...2 {
            if possibilityMatrix[boxLocation.0 + y, boxLocation.1 + x][0] == number {
                return true
            }
        }
    }
    return false
}

The problem is that you're checking probabilityMatrix to see if the number exists - which is the variable that you are modifying as you go. So if you change probabilityMatrix[0, 0] to equal [4, 5], then when you check probabilityMatrix[0, 1], your functions will assume that 4 is in that first row, because of the change you just made. Part of its check is looking at the first element of probabilityMatrix[0, 0], which is 4, so your code thinks that the first row naturally has a 4 in it.

After enough of this, you will eventually get to a square where the list of possibilities is [], because the erroneous numbers accumulate as you go along a row (or column or box) and eventually all possibilities disappear. Then on the very next pass, a function like rowContains will look at that [] and try to get the first element from it (like in possibilityMatrix[r, i][0]), which doesn't exist. This is the cause of your Index out of range error.

The solution is to compare to field instead of possibilityMatrix, since that variable never changes and always holds the original matrix. So your functions should look like this:

func rowContains(r: Int, number: Int) -> Bool {
    for i in 0...8 {
        if field[r, i][0] == number {
            return true
        }
    }
    return false
}
func columnContains(c: Int, number: Int) -> Bool {
   for i in 0...8 {
        if field[i, c][0] == number {
            return true
        }
    }
    return false
}
func boxContains (r: Int, c: Int, number: Int) -> Bool {
    let boxLocation = locateBox(r, c: c)
    for x in 0...2 {
        for y in 0...2 {
            if field[boxLocation.0 + y, boxLocation.1 + x][0] == number {
                return true
            }
        }
    }
    return false
}

Here's the working version implemented in the Sandbox for you to look at:

http://swiftlang.ng.bluemix.net/#/repl/6fe779409351531ce07d3bc3f0c197639538729b40d5f0f658e4dd53985223fe

EDIT: while learning recursion is a good thing, it's also good to avoid it if you can, since it takes up more resources than an iterative loop (since each time you call a function, it's placed on the program stack and takes up resources). Here's a faster way of achieving the same result:

func locateBox (r: Int, c: Int) -> (upBorder: Int, leftBorder: Int) {
    return ((r - (r % 3)), (c - (c % 3)))
}

Also, your fillPossibilityMatrix() function might work better as a double loop, since 1) the division and remainder functions are a little bit computationally expensive, and 2) it's easier to read.

func fillPossibilityMatrix() {        //it's a 9x9 Matrix
    for row in 0...8 {
        for column in 0...8 {                        
            if possibilityMatrix[row, column] == [0] {
                possibilityMatrix[row, column] = possibilities(row, column: column)
            }
        }
    }
}
TheSoundDefense
  • 6,753
  • 1
  • 30
  • 42
  • Thank you! This did it. I got it running now - if anybody cares: http://swiftlang.ng.bluemix.net/#/repl/26c7948d09498a283c1c5ec8d13c245aa235ff821213f5a0163df8a22fc79894 – simsula Dec 21 '15 at 13:30