From 64e46b55efb34a5b11e09842a73dea12751db773 Mon Sep 17 00:00:00 2001 From: Alexis Drai Date: Thu, 9 Feb 2023 16:38:25 +0100 Subject: [PATCH] :rotating_light: :recycle: Clean up and simplify basic rules class --- .../rules/BasicDefaultsNoDiag.swift | 181 +++++++++--------- .../BasicDefaultNoDiagTest.swift | 2 +- 2 files changed, 87 insertions(+), 96 deletions(-) diff --git a/Connect4/connect4_lib/Sources/connect4_lib/rules/BasicDefaultsNoDiag.swift b/Connect4/connect4_lib/Sources/connect4_lib/rules/BasicDefaultsNoDiag.swift index a78e700..3a0eb52 100644 --- a/Connect4/connect4_lib/Sources/connect4_lib/rules/BasicDefaultsNoDiag.swift +++ b/Connect4/connect4_lib/Sources/connect4_lib/rules/BasicDefaultsNoDiag.swift @@ -38,36 +38,62 @@ public struct BasicDefaultsNoDiag : IRules { public func getNextPlayer(fromGrid grid: [[Int?]], withPlayer1Id p1id: Int, withPlayer2Id p2id: 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 tile in row { - if let tile { // not nil - if tile == p1id { p1ctr += 1 } - if tile == p2id { p2ctr += 1 } + if tile == nil { + return false } } } - - // player 1 will always start - - if p1ctr <= p2ctr { return p1id } // but it should only ever be == or > ... - else { return p2id } + return true } + 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.. (isOver: Bool, result: Result) { // first check if board is full - var isFull = true - for row in grid { - for tile in row { - if tile == nil { - isFull = false - break - } - } - } + let isFull = isFull(grid) var victoryTiles : [(Int, Int)] = Array(repeating: (0, 0), count: nbChipsToAlign) @@ -77,97 +103,62 @@ public struct BasicDefaultsNoDiag : IRules { for i in 0..= nbChipsToAlign && grid[i][j] != nil && grid[i][j] == playerId { - - // check for victory - let amountAligned = checkAligned(byPlayer: playerId, - onGrid: grid, - fromRow: i, - 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 && tile == playerId && checkVictory(byPlayer: playerId, + onGrid: grid, + fromRow: i, + fromCol: j, + going: .right, + victoryTiles: &victoryTiles) { + return (isOver: true, Result.won(playerId, victoryTiles)) } - - // check if there is room lower down - if (nbRows - i) >= nbChipsToAlign && grid[i][j] != nil && grid[i][j] == playerId { - - // check for victory - let amountAligned = checkAligned(byPlayer: playerId, - onGrid: grid, - 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 && tile == playerId && checkVictory(byPlayer: playerId, + onGrid: grid, + fromRow: i, + fromCol: j, + going: .down, + victoryTiles: &victoryTiles) { + return (isOver: true, Result.won(playerId, victoryTiles)) } } } - if(isFull) { - return (isOver: true, Result.deadlocked); - } else { - return (isOver: false, Result.notOver) - } + return (isOver: isFull, + isFull ? Result.deadlocked : Result.notOver); } private func checkAligned(byPlayer playerId: Int, - onGrid grid: [[Int?]], - fromRow i: Int, - upToRow iMax: Int, - andCol j: Int, - upToCol jMax: Int, - going direction: directions) -> Int { - if let tile = grid[i][j] { - if tile == playerId { - if direction == directions.right { - if j == jMax { return 1 } - return 1 + checkAligned(byPlayer: playerId, - onGrid: grid, - fromRow: i, - upToRow: iMax, - andCol: j + 1, - upToCol: jMax, - going: direction) + onGrid grid: [[Int?]], + fromRow i: Int, + fromCol j: Int, + going direction: Direction) -> Int { + let iMax = grid.count - 1 + let jMax = grid[0].count - 1 + + if let tile = grid[i][j], tile == playerId { + if direction == .right { + if j == jMax { + return 1 + } + return 1 + checkAligned(byPlayer: playerId, + onGrid: grid, + fromRow: i, + fromCol: j + 1, + going: direction) - } else if direction == directions.down { - if i == iMax { return 1 } - return 1 + checkAligned(byPlayer: playerId, - onGrid: grid, - fromRow: i + 1, - upToRow: iMax, - andCol: j, - upToCol: jMax, - going: direction) + } else if direction == .down { + if i == iMax { + return 1 } + return 1 + checkAligned(byPlayer: playerId, + onGrid: grid, + fromRow: i + 1, + fromCol: j, + going: direction) } } return 0 } - private enum directions { + private enum Direction { case right case down } diff --git a/Connect4/connect4_lib/Tests/connect4_libTests/BasicDefaultNoDiagTest.swift b/Connect4/connect4_lib/Tests/connect4_libTests/BasicDefaultNoDiagTest.swift index 3a63a15..8951d7f 100644 --- a/Connect4/connect4_lib/Tests/connect4_libTests/BasicDefaultNoDiagTest.swift +++ b/Connect4/connect4_lib/Tests/connect4_libTests/BasicDefaultNoDiagTest.swift @@ -102,7 +102,7 @@ final class BasicDefaultNoDiagTest: XCTestCase { [nil, 2, 1], [nil, 2, 1]], resultShouldBe: .won(1, [(0, 2), (1, 2), (2, 2)])) - + expect(byPlayer: 1, withGrid: [[1, 2, 1], [1, 2, 1],