From e519b07cf55ea33229da9fc504f30e245b3b59e9 Mon Sep 17 00:00:00 2001 From: Alexis Drai Date: Wed, 1 Feb 2023 11:56:37 +0100 Subject: [PATCH] :construction: :necktie: WIP Players, Rules, Games, Boards --- Connect4/connect4_cli/connect4_cli/main.swift | 11 ++++++++ .../Sources/connect4_lib/games/Game.swift | 27 +++++++++++++++++++ .../Sources/connect4_lib/players/Bot.swift | 9 +++++-- .../Sources/connect4_lib/players/Human.swift | 10 +++++++ .../Sources/connect4_lib/players/Player.swift | 14 +++++----- .../connect4_lib/players/SmarterBot.swift | 4 --- .../rules/BasicDefaultsNoDiag.swift | 13 +++++---- .../Sources/connect4_lib/rules/IRules.swift | 19 +++++++++++-- 8 files changed, 87 insertions(+), 20 deletions(-) create mode 100644 Connect4/connect4_lib/Sources/connect4_lib/games/Game.swift delete mode 100644 Connect4/connect4_lib/Sources/connect4_lib/players/SmarterBot.swift diff --git a/Connect4/connect4_cli/connect4_cli/main.swift b/Connect4/connect4_cli/connect4_cli/main.swift index 6509ed1..9ddd902 100644 --- a/Connect4/connect4_cli/connect4_cli/main.swift +++ b/Connect4/connect4_cli/connect4_cli/main.swift @@ -16,3 +16,14 @@ if var b = Board(withRows: 3, andWithCols: 3) { status = b.insertChip(from: 1, atCol: 1) print(b) } + +public func scan() -> Int { + // board.dispokayBoard() + // print("player \(rules.getNextPlayer()), choose a column between ") + var res: Int? = nil + while(res == nil) { + let str = readLine() + res = Int(str ?? "") + } + return res! +} diff --git a/Connect4/connect4_lib/Sources/connect4_lib/games/Game.swift b/Connect4/connect4_lib/Sources/connect4_lib/games/Game.swift new file mode 100644 index 0000000..0b6a4f0 --- /dev/null +++ b/Connect4/connect4_lib/Sources/connect4_lib/games/Game.swift @@ -0,0 +1,27 @@ +import Foundation +class Game { + private let scanner: () -> Int + private let displayBoard: () -> String + private let board: Board + private let rules: IRules + private let player1: Player + private let player2: Player + + init(withScanner scanner: @escaping () -> Int, + withBoard board: Board, + withRules rules: IRules, + withPlayer1 player1: Player, + withPlayer2 player2: Player) { + self.scanner = scanner + self.displayBoard = { () -> String in + return board.description + } + // TODO check that board is valid using the rules + self.board = board + self.rules = rules + self.player1 = player1 + self.player2 = player2 + } + + +} diff --git a/Connect4/connect4_lib/Sources/connect4_lib/players/Bot.swift b/Connect4/connect4_lib/Sources/connect4_lib/players/Bot.swift index 68b92b6..c5a7f88 100644 --- a/Connect4/connect4_lib/Sources/connect4_lib/players/Bot.swift +++ b/Connect4/connect4_lib/Sources/connect4_lib/players/Bot.swift @@ -1,7 +1,12 @@ import Foundation class Bot: Player { - override func playBetween(min: Int, andMaxIncl maxIncl: Int) -> Int { - return Int.random(in: min.. Int? { + return Int.random(in: 0.. Int? + + init(withId id: Int, withName name: String, usingScanner scanner: @escaping () -> Int?){ + self.scanner = scanner + super.init(withId: id, withName: name) + } + + override func chooseColumn(inBoard board: Board, withRules rules: IRules) -> Int? { + return scanner() + } } diff --git a/Connect4/connect4_lib/Sources/connect4_lib/players/Player.swift b/Connect4/connect4_lib/Sources/connect4_lib/players/Player.swift index 66b487d..ed9c1d9 100644 --- a/Connect4/connect4_lib/Sources/connect4_lib/players/Player.swift +++ b/Connect4/connect4_lib/Sources/connect4_lib/players/Player.swift @@ -2,17 +2,17 @@ import Foundation class Player { - let id: Int + private let id: Int + private let name: String - init(withId id: Int){ + init(withId id: Int, withName name: String){ self.id = id + self.name = name } - - /// + /// should be considered abstract and overridden by descendants - internal func playBetween(min: Int, andMaxIncl maxIncl: Int) -> Int { - return -1 + func chooseColumn(inBoard board: Board, withRules rules: IRules) -> Int? { + return nil } } - diff --git a/Connect4/connect4_lib/Sources/connect4_lib/players/SmarterBot.swift b/Connect4/connect4_lib/Sources/connect4_lib/players/SmarterBot.swift deleted file mode 100644 index dfaea87..0000000 --- a/Connect4/connect4_lib/Sources/connect4_lib/players/SmarterBot.swift +++ /dev/null @@ -1,4 +0,0 @@ -import Foundation -class SmarterBot: Bot { - -} diff --git a/Connect4/connect4_lib/Sources/connect4_lib/rules/BasicDefaultsNoDiag.swift b/Connect4/connect4_lib/Sources/connect4_lib/rules/BasicDefaultsNoDiag.swift index 1917129..d529567 100644 --- a/Connect4/connect4_lib/Sources/connect4_lib/rules/BasicDefaultsNoDiag.swift +++ b/Connect4/connect4_lib/Sources/connect4_lib/rules/BasicDefaultsNoDiag.swift @@ -31,7 +31,7 @@ public struct BasicDefaultsNoDiag : IRules { } public func isGameOver(byPlayer playerId: Int, onGrid grid: [[Int?]]) - -> (isOver: Bool, hasWinner: Bool, victoryTiles: [(Int, Int)]?) { + -> (isOver: Bool, result: Result) { // first check if board is full var isFull = true @@ -72,7 +72,7 @@ public struct BasicDefaultsNoDiag : IRules { // row i, origin is (i, j), goes to the right victoryTiles[x] = (i, j + x) } - return (isOver: true, hasWinner: true, victoryTiles) + return (isOver: true, Result.won(playerId, victoryTiles)) } } @@ -96,13 +96,16 @@ public struct BasicDefaultsNoDiag : IRules { // column j, origin is (i, j), goes down victoryTiles[x] = (i + x, j) } - return (isOver: true, hasWinner: true, victoryTiles) + return (isOver: true, Result.won(playerId, victoryTiles)) } } } } - - return (isFull, hasWinner: false, nil); + if(isFull) { + return (isOver: true, Result.deadlocked); + } else { + return (isOver: false, Result.notOver) + } } private func checkAligned(byPlayer playerId: Int, diff --git a/Connect4/connect4_lib/Sources/connect4_lib/rules/IRules.swift b/Connect4/connect4_lib/Sources/connect4_lib/rules/IRules.swift index 4a5f943..1ac68ac 100644 --- a/Connect4/connect4_lib/Sources/connect4_lib/rules/IRules.swift +++ b/Connect4/connect4_lib/Sources/connect4_lib/rules/IRules.swift @@ -1,10 +1,25 @@ import Foundation -protocol IRules { +public protocol IRules { var minNbRows: Int { get } var maxNbRows: Int { get } var minNbCols: Int { get } var maxNbCols: Int { get } var nbChipsToAlign: Int { get } - func isGameOver(byPlayer playerId: Int, onGrid grid: [[Int?]]) -> (isOver: Bool, hasWinner: Bool, victoryTiles: [(Int, Int)]?) + func isGameOver(byPlayer playerId: Int, onGrid grid: [[Int?]]) -> (isOver: Bool, result: Result) + // TODO plug in the EnumResult + // and + // isGameOver(c) -> (Bool, EnumResult) + // getNextPlayer(c) -> Int + // isValid(c) -> Bool + +} + +public enum Result { + case notOver + case deadlocked + + // playerId, victoryTiles + case won(Int, [(Int, Int)]?) + }