🚨 ♻️ Clean up and simplify basic rules class
continuous-integration/drone/push Build is passing Details

main
Alexis Drai 2 years ago
parent 4e505be8a8
commit 64e46b55ef

@ -38,36 +38,62 @@ public struct BasicDefaultsNoDiag : IRules {
public func getNextPlayer(fromGrid grid: [[Int?]], withPlayer1Id p1id: Int, withPlayer2Id p2id: Int) public func getNextPlayer(fromGrid grid: [[Int?]], withPlayer1Id p1id: Int, withPlayer2Id p2id: Int)
-> Int { -> Int {
var p1ctr = 0, p2ctr = 0 // player 1 will always start
let playerCounters = grid
.flatMap { $0 }
.compactMap { $0 }
.reduce([p1id: 0, p2id: 0]) { (inCounters, tile) in
var counters = inCounters
counters[tile, default: 0] += 1
return counters
}
return playerCounters[p1id] ?? 0 <= playerCounters[p2id] ?? 0
? p1id
: p2id
}
private func isFull(_ grid: [[Int?]]) -> Bool {
for row in grid { for row in grid {
for tile in row { for tile in row {
if let tile { // not nil if tile == nil {
if tile == p1id { p1ctr += 1 } return false
if tile == p2id { p2ctr += 1 }
} }
} }
} }
return true
// player 1 will always start
if p1ctr <= p2ctr { return p1id } // but it should only ever be == or > ...
else { return p2id }
} }
private func checkVictory(byPlayer playerId: Int,
onGrid grid: [[Int?]],
fromRow: Int,
fromCol: Int,
going direction: Direction,
victoryTiles: inout [(Int, Int)]) -> Bool {
let amountAligned = checkAligned(byPlayer: playerId,
onGrid: grid,
fromRow: fromRow,
fromCol: fromCol,
going: direction)
if amountAligned >= nbChipsToAlign {
for x in 0..<nbChipsToAlign {
if direction == .right {
victoryTiles[x] = (fromRow, fromCol + x)
} else if direction == .down {
victoryTiles[x] = (fromRow + x, fromCol)
}
}
return true
}
return false
}
public func isGameOver(byPlayer playerId: Int, onGrid grid: [[Int?]]) public func isGameOver(byPlayer playerId: Int, onGrid grid: [[Int?]])
-> (isOver: Bool, result: Result) { -> (isOver: Bool, result: Result) {
// first check if board is full // first check if board is full
var isFull = true let isFull = isFull(grid)
for row in grid {
for tile in row {
if tile == nil {
isFull = false
break
}
}
}
var victoryTiles : [(Int, Int)] = Array(repeating: (0, 0), count: nbChipsToAlign) var victoryTiles : [(Int, Int)] = Array(repeating: (0, 0), count: nbChipsToAlign)
@ -77,97 +103,62 @@ public struct BasicDefaultsNoDiag : IRules {
for i in 0..<nbRows { for i in 0..<nbRows {
for j in 0..<nbCols { for j in 0..<nbCols {
// check if there is room to the right if let tile = grid[i][j], (nbCols - j) >= nbChipsToAlign && tile == playerId && checkVictory(byPlayer: playerId,
if (nbCols - j) >= nbChipsToAlign && grid[i][j] != nil && grid[i][j] == playerId { onGrid: grid,
fromRow: i,
// check for victory fromCol: j,
let amountAligned = checkAligned(byPlayer: playerId, going: .right,
onGrid: grid, victoryTiles: &victoryTiles) {
fromRow: i, return (isOver: true, Result.won(playerId, victoryTiles))
upToRow: (nbRows - 1),
andCol: j,
upToCol: (nbCols - 1),
going: directions.right)
//print("player \(String(describing: Board.descriptionMapper[playerId])) aligned \(amountAligned) horizontally:")
if amountAligned >= nbChipsToAlign {
for x in 0..<nbChipsToAlign {
// row i, origin is (i, j), goes to the right
victoryTiles[x] = (i, j + x)
}
return (isOver: true, Result.won(playerId, victoryTiles))
}
} }
if let tile = grid[i][j], (nbRows - i) >= nbChipsToAlign && tile == playerId && checkVictory(byPlayer: playerId,
// check if there is room lower down onGrid: grid,
if (nbRows - i) >= nbChipsToAlign && grid[i][j] != nil && grid[i][j] == playerId { fromRow: i,
fromCol: j,
// check for victory going: .down,
let amountAligned = checkAligned(byPlayer: playerId, victoryTiles: &victoryTiles) {
onGrid: grid, return (isOver: true, Result.won(playerId, victoryTiles))
fromRow: i,
upToRow: (nbRows - 1),
andCol: j,
upToCol: (nbCols - 1),
going: directions.down)
//print("player \(String(describing: Board.descriptionMapper[playerId])) aligned \(amountAligned) vertically:")
if amountAligned >= nbChipsToAlign {
for x in 0..<nbChipsToAlign {
// column j, origin is (i, j), goes down
victoryTiles[x] = (i + x, j)
}
return (isOver: true, Result.won(playerId, victoryTiles))
}
} }
} }
} }
if(isFull) { return (isOver: isFull,
return (isOver: true, Result.deadlocked); isFull ? Result.deadlocked : Result.notOver);
} else {
return (isOver: false, Result.notOver)
}
} }
private func checkAligned(byPlayer playerId: Int, private func checkAligned(byPlayer playerId: Int,
onGrid grid: [[Int?]], onGrid grid: [[Int?]],
fromRow i: Int, fromRow i: Int,
upToRow iMax: Int, fromCol j: Int,
andCol j: Int, going direction: Direction) -> Int {
upToCol jMax: Int, let iMax = grid.count - 1
going direction: directions) -> Int { let jMax = grid[0].count - 1
if let tile = grid[i][j] {
if tile == playerId { if let tile = grid[i][j], tile == playerId {
if direction == directions.right { if direction == .right {
if j == jMax { return 1 } if j == jMax {
return 1 + checkAligned(byPlayer: playerId, return 1
onGrid: grid, }
fromRow: i, return 1 + checkAligned(byPlayer: playerId,
upToRow: iMax, onGrid: grid,
andCol: j + 1, fromRow: i,
upToCol: jMax, fromCol: j + 1,
going: direction) going: direction)
} else if direction == directions.down { } else if direction == .down {
if i == iMax { return 1 } if i == iMax {
return 1 + checkAligned(byPlayer: playerId, return 1
onGrid: grid,
fromRow: i + 1,
upToRow: iMax,
andCol: j,
upToCol: jMax,
going: direction)
} }
return 1 + checkAligned(byPlayer: playerId,
onGrid: grid,
fromRow: i + 1,
fromCol: j,
going: direction)
} }
} }
return 0 return 0
} }
private enum directions { private enum Direction {
case right case right
case down case down
} }

@ -102,7 +102,7 @@ final class BasicDefaultNoDiagTest: XCTestCase {
[nil, 2, 1], [nil, 2, 1],
[nil, 2, 1]], [nil, 2, 1]],
resultShouldBe: .won(1, [(0, 2), (1, 2), (2, 2)])) resultShouldBe: .won(1, [(0, 2), (1, 2), (2, 2)]))
expect(byPlayer: 1, expect(byPlayer: 1,
withGrid: [[1, 2, 1], withGrid: [[1, 2, 1],
[1, 2, 1], [1, 2, 1],

Loading…
Cancel
Save