|
|
|
@ -4,40 +4,38 @@ public struct Board : CustomStringConvertible {
|
|
|
|
|
|
|
|
|
|
public let nbRows: Int
|
|
|
|
|
public let nbCols: Int
|
|
|
|
|
private var nbFree: Int
|
|
|
|
|
private var grid: [[Int?]]
|
|
|
|
|
public var grid : [[Int?]] { _grid }
|
|
|
|
|
var _nbFree: Int
|
|
|
|
|
var _grid: [[Int?]]
|
|
|
|
|
|
|
|
|
|
public init?(withRows nbRows: Int = 6, andWithCols nbCols: Int = 7) {
|
|
|
|
|
guard(nbRows > 0 && nbCols > 0) else { return nil }
|
|
|
|
|
self.nbRows = nbRows
|
|
|
|
|
self.nbCols = nbCols
|
|
|
|
|
self.nbFree = nbRows * nbCols
|
|
|
|
|
self.grid = Array(repeating: Array(repeating: nil, count: nbCols), count: nbRows)
|
|
|
|
|
self._nbFree = nbRows * nbCols
|
|
|
|
|
self._grid = Array(repeating: Array(repeating: nil, count: nbCols), count: nbRows)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public init?(withGrid grid: [[Int?]]) {
|
|
|
|
|
guard(grid.allSatisfy{ $0.count == grid[0].count }) else { return nil }
|
|
|
|
|
self.nbRows = grid.count
|
|
|
|
|
self.nbCols = grid[0].count
|
|
|
|
|
self.nbFree = nbRows * nbCols
|
|
|
|
|
self.grid = grid
|
|
|
|
|
self._nbFree = nbRows * nbCols
|
|
|
|
|
self._grid = grid
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private func isWithinBounds(_ row: Int, and col: Int) -> Bool {
|
|
|
|
|
func isWithinBounds(_ row: Int, and col: Int) -> Bool {
|
|
|
|
|
return 0 <= row && row < nbRows
|
|
|
|
|
&& 0 <= col && col < nbCols
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static let descriptionMapper : [Int? : String] = [nil : "-", 1 : "X", 2: "O"]
|
|
|
|
|
|
|
|
|
|
public var description: String {
|
|
|
|
|
var string = String()
|
|
|
|
|
for row in grid {
|
|
|
|
|
for row in _grid {
|
|
|
|
|
for tile in row {
|
|
|
|
|
string.append(" ")
|
|
|
|
|
switch(tile) {
|
|
|
|
|
case 1: string.append("O")
|
|
|
|
|
case 2: string.append("X")
|
|
|
|
|
default: string.append("_")
|
|
|
|
|
}
|
|
|
|
|
string.append("\(String(describing: Board.descriptionMapper[tile] ?? "-"))")
|
|
|
|
|
}
|
|
|
|
|
string.append("\n")
|
|
|
|
|
}
|
|
|
|
@ -45,24 +43,24 @@ public struct Board : CustomStringConvertible {
|
|
|
|
|
return string
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private mutating func insertChip(from playerId: Int, atRow row: Int, atCol col: Int) -> Bool {
|
|
|
|
|
mutating func insertChip(from playerId: Int, atRow row: Int, atCol col: Int) -> Bool {
|
|
|
|
|
guard(isWithinBounds(row, and: col)) else { return false }
|
|
|
|
|
guard((playerId == 1 || playerId == 2)) else { return false }
|
|
|
|
|
guard(!isFull()) else { return false }
|
|
|
|
|
guard((grid[row][col] == nil)) else { return false }
|
|
|
|
|
guard((_grid[row][col] == nil)) else { return false }
|
|
|
|
|
|
|
|
|
|
grid[row][col] = playerId
|
|
|
|
|
nbFree -= 1
|
|
|
|
|
_grid[row][col] = playerId
|
|
|
|
|
_nbFree -= 1
|
|
|
|
|
return true
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public mutating func insertChip(from playerId: Int, atCol col: Int) -> Bool {
|
|
|
|
|
guard(0 < col && col <= nbCols) else { return false }
|
|
|
|
|
|
|
|
|
|
if grid[0][col] != nil { return false }
|
|
|
|
|
if _grid[0][col] != nil { return false }
|
|
|
|
|
|
|
|
|
|
for i in stride(from: nbRows - 1, through: 0, by: -1) {
|
|
|
|
|
if grid[i][col] == nil {
|
|
|
|
|
if _grid[i][col] == nil {
|
|
|
|
|
return insertChip(from: playerId, atRow: i, atCol: col)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@ -70,14 +68,15 @@ public struct Board : CustomStringConvertible {
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private mutating func removeChip(fromRow row: Int, fromCol col: Int) {
|
|
|
|
|
mutating func removeChip(fromRow row: Int, fromCol col: Int) {
|
|
|
|
|
assert(isWithinBounds(row, and: col))
|
|
|
|
|
grid[row][col] = nil
|
|
|
|
|
nbFree += 1
|
|
|
|
|
_grid[row][col] = nil
|
|
|
|
|
_nbFree += 1
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public func isFull() -> Bool {
|
|
|
|
|
return nbFree <= 0
|
|
|
|
|
return _nbFree <= 0
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|