Number Place and Swift 3 (4)

backtrack2

Of course, we do not select the position to be filled randomly or sequentially, but more intelligently to save our energy. One method is to select the place with minimum number of possibilities.

    func findPosition(table: [[Int]]) -> Position {
        var workPlaces   = [Place]()
        var sortedPlaces = [Place]()
        var position = Position()
        var place = Place()
            for cc in 0...8 {
                for rr in 0...8 {
                if table[rr][cc] == 0 {
                    position.row = rr
                    position.col = cc
                    place.position = position
                    place.val    = eval(position: position, table: table)
                    workPlaces.append(place)
                }
            }
        }
        sortedPlaces = workPlaces.sorted( by: { $0.val < $1.val } )
        place = sortedPlaces[0]
        position = place.position
        return position
    }

Actually, there is no need to reevaluate the all positions every time. Only those affected by the last move should be considered.

backtrac3

The recursive function, dropNum is now called only 139 times with the same problem.

struct Position {
    var row: Int = -1
    var col: Int = -1
}
struct Place {
    var position = Position()
    var val: Int = 0
}

class NumBoard {
    var table         = [[Int]]()
    var emptyPlaces   = [Place]()
    var sortedPlaces  = [Place]()
    var putPositions  = [Position]()
    var position      = Position()
    var place         = Place()
    var nplaces : Int = 0
    
    init() {
        table = [[7,0,3, 0,0,0, 0,0,0],
                 [0,5,1, 3,7,0, 4,0,0],
                 [6,0,0, 0,1,0, 0,2,0],
                 [0,0,4, 6,0,0, 0,0,0],
                 [0,0,0, 0,0,7, 0,8,0],
                 [5,0,0, 2,3,1, 9,0,0],
                 [3,0,0, 0,2,4, 0,9,1],
                 [0,0,0, 0,0,0, 8,4,0],
                 [0,0,7, 0,9,0, 2,0,0]]

        for rr in 0...8 {
            for cc in 0...8 {
                if table[rr][cc] == 0 {
                    nplaces += 1
                }
            }
        }
        myprint(table: table)
        print("nplaces = \(nplaces)")
    }
    
    func myprint(table: [[Int]]) {
        print("-----------------")
        for rr in 0...8 {
            for cc in 0...8 {
                if table[rr][cc] == 0 {
                    print(".", terminator: " ")
                } else {
                    print(table[rr][cc], terminator: " ")
                }
            }
            print("")
        }
        print("-----------------")
    }
    
    func eval(position: Position, table: [[Int]]) -> Int {
        var count = 0
        for num in 1...9 {
            if isSafeForNum(position: position, num: num) {
                count += 1
            }
        }
        return count
    }
    
    func isSafeForNum(position: Position, num: Int) -> Bool {
        for rr in 0...8 {
            if num == table[rr][position.col] { return false }
        }
        for cc in 0...8 {
            if num == table[position.row][cc] { return false }
        }
        let rowBase = (position.row / 3) * 3
        let colBase = (position.col / 3) * 3
        for rr in 0...2 {
            for cc in 0...2 {
                if num == table[rowBase+rr][colBase+cc] { return false }
            }
        }
        return true
    }

    func findPosition(table: [[Int]]) -> Position {
        var workPlaces   = [Place]()
        var sortedPlaces = [Place]()
        var position = Position()
        var place = Place()
            for cc in 0...8 {
                for rr in 0...8 {
                if table[rr][cc] == 0 {
                    position.row = rr
                    position.col = cc
                    place.position = position
                    place.val    = eval(position: position, table: table)
                    workPlaces.append(place)
                }
            }
        }
        sortedPlaces = workPlaces.sorted( by: { $0.val < $1.val } )
        place = sortedPlaces[0]
        position = place.position
        return position
    }
    
    func dropNum(index: Int) {
        position = findPosition(table: table)
        for num in 1...9 {
            if isSafeForNum(position: position, num: num) {
                table[position.row][position.col] = num
                putPositions.append(position)
                if putPositions.count == nplaces { return }
                dropNum(index: index+1)
                if putPositions.count != nplaces {
                    position = putPositions[putPositions.count - 1]
                    table[position.row][position.col] = 0
                    putPositions.removeLast()
                }
            }
        }
    }
    
    func play() {
        dropNum(index: 0)
        myprint(table: table)
    }
}

// main program
let myboard = NumBoard()
myboard.play()

Leave a Reply

Your email address will not be published. Required fields are marked *