diff --git a/DouShouQiConsole/DouShouQiConsole/main.swift b/DouShouQiConsole/DouShouQiConsole/main.swift index 1fd4d47..1b7749b 100644 --- a/DouShouQiConsole/DouShouQiConsole/main.swift +++ b/DouShouQiConsole/DouShouQiConsole/main.swift @@ -91,3 +91,62 @@ if var board = Board(withGrid: initialBoardConfiguration) { } else { print("Erreur lors de l'initialisation du plateau de jeu.") } + + +// Création des règles et du plateau initial +var rules = VerySimpleRules() +var board = VerySimpleRules.createBoard() + + +/* +// Simulation du mouvement sur le plateau +if let piece = oldBoard.grid[move.rowOrigin][move.columnOrigin].piece { + newBoard.grid[move.rowDestination][move.columnDestination].piece = piece + newBoard.grid[move.rowOrigin][move.columnOrigin].piece = nil +} +*/ + +/* +// Création des joueurs +let humanPlayer = HumanPlayer(name: "Joueur Humain", id: .player1) { board, rules in + // Logique pour permettre à l'utilisateur de choisir un mouvement + print("Votre mouvement (format 'rowOrigin, columnOrigin, rowDestination, columnDestination') :") + if let input = readLine() { + let components = input.split(separator: ",").compactMap { Int($0.trimmingCharacters(in: .whitespacesAndNewlines)) } + if components.count == 4 { + return Move(owner: .player1, rowOrigin: components[0], columnOrigin: components[1], rowDestination: components[2], columnDestination: components[3]) + } + } + return nil +} + +let randomPlayer = RandomPlayer(withName: "Joueur IA", andId: .player2) + + let human = humanPlayer, let random = randomPlayer else { + print("Erreur lors de la création des joueurs.") +} + +while true { + // Afficher l'état actuel du plateau + print(board) + + // Déterminer le joueur actuel + let currentPlayer = rules.getNextPlayer() == human.id ? human : random + + // Le joueur actuel choisit un mouvement + if let move = currentPlayer.chooseMove(board: board, rules: rules), rules.isMoveValid(board: board, move: move) { + // Appliquer le mouvement et mettre à jour le plateau + rules.playedMove(move: move, oldBoard: board, newBoard: board) + + // Vérifier si le jeu est terminé + let gameOverResult = rules.isGameOver(board: board, lastMove: move) + if gameOverResult.0 { + print("Le jeu est terminé. Résultat : \(gameOverResult.1)") + break + } + } else { + print("Mouvement invalide. Essayez de nouveau.") + } +} + +*/ diff --git a/Model/.swiftpm/xcode/xcshareddata/xcschemes/ModelCov.xcscheme b/Model/.swiftpm/xcode/xcshareddata/xcschemes/ModelCov.xcscheme new file mode 100644 index 0000000..a4b7bad --- /dev/null +++ b/Model/.swiftpm/xcode/xcshareddata/xcschemes/ModelCov.xcscheme @@ -0,0 +1,83 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Model/Sources/Model/Board.swift b/Model/Sources/Model/Board.swift index 31ea126..c3afd2a 100644 --- a/Model/Sources/Model/Board.swift +++ b/Model/Sources/Model/Board.swift @@ -7,7 +7,7 @@ import Foundation -public struct Board : CustomStringConvertible, Hashable, Equatable { +public struct Board : Hashable, Equatable { public let nbRows: Int public let nbColumns: Int public private(set) var grid: [[Cell]] @@ -65,16 +65,7 @@ public struct Board : CustomStringConvertible, Hashable, Equatable { } } - public var description: String { - var boardDescription = "" - for row in grid { - for cell in row { - boardDescription += cell.description + " " - } - boardDescription += "\n" - } - return boardDescription - } + } diff --git a/Model/Sources/Model/Interface/Rules.swift b/Model/Sources/Model/Interface/Rules.swift index 44ded24..19ceba1 100644 --- a/Model/Sources/Model/Interface/Rules.swift +++ b/Model/Sources/Model/Interface/Rules.swift @@ -28,5 +28,5 @@ public protocol Rules { func isGameOver( board: Board, lastMove: Move) -> (Bool, Result) // permet de stocker le coût qui a été fait. (playedMove) - func playedMove(move: Move, oldBoard: Board, newBoard: Board) + mutating func playedMove(move: Move, oldBoard: Board, newBoard: Board) } diff --git a/Model/Sources/Model/Move.swift b/Model/Sources/Model/Move.swift index 80abf9d..48ef412 100644 --- a/Model/Sources/Model/Move.swift +++ b/Model/Sources/Model/Move.swift @@ -13,4 +13,17 @@ public struct Move { public let columnOrigin: Int public let rowDestination: Int public let columnDestination: Int + + public init(owner: Owner, rowOrigin: Int, columnOrigin: Int, rowDestination: Int, columnDestination: Int) { + self.owner = owner + self.rowOrigin = rowOrigin + self.columnOrigin = columnOrigin + self.rowDestination = rowDestination + self.columnDestination = columnDestination + } + + public var description: String { + let description = "Move by \(owner): (\(rowOrigin) / \(columnOrigin)) to (\(rowDestination) / \(columnDestination))" + return description + } } diff --git a/Model/Sources/Model/RandomPlayer.swift b/Model/Sources/Model/RandomPlayer.swift index cc256fe..28a19dc 100644 --- a/Model/Sources/Model/RandomPlayer.swift +++ b/Model/Sources/Model/RandomPlayer.swift @@ -9,6 +9,11 @@ import Foundation public class RandomPlayer: Player { + public init?(withName name: String, andId id:Owner) + { + super.init(name: name, id: id) + } + public override func chooseMove(board: Board, rules: VerySimpleRules) -> Move? { let validMoves = rules.getMoves(board: board, owner: self.id) return validMoves.randomElement() // Sélectionne un mouvement aléatoire parmi les mouvements valides diff --git a/Model/Sources/Model/VerySimpleRules.swift b/Model/Sources/Model/VerySimpleRules.swift index 12f40ad..eae7be5 100644 --- a/Model/Sources/Model/VerySimpleRules.swift +++ b/Model/Sources/Model/VerySimpleRules.swift @@ -8,10 +8,15 @@ import Foundation public struct VerySimpleRules: Rules { - + public var occurences = [Board: Int]() public var historic = [Move]() + public init() { + self.occurences = [Board: Int]() + self.historic = [Move]() + } + public static func createBoard() -> Board { var cells = [[Cell]]() @@ -123,9 +128,6 @@ public struct VerySimpleRules: Rules { return false } - // Autres vérifications spécifiques au jeu peuvent être ajoutées ici - // ... - return true } @@ -171,12 +173,9 @@ public struct VerySimpleRules: Rules { return (false, .notFinished) } - public func playedMove(move: Move, oldBoard: Board, newBoard: Board) { - // ToDo + public mutating func playedMove(move: Move, oldBoard: Board, newBoard: Board) { // Ajouter le mouvement à l'historique - // historic.append(move) - - // Mise à jour du comptage des occurrences pour le nouveau plateau - // occurences[newBoard, default: 0] += 1 + historic.append(move) } } + diff --git a/Model/Tests/ModelTests/PlayerTests.swift b/Model/Tests/ModelTests/PlayerTests.swift new file mode 100644 index 0000000..53b2a9b --- /dev/null +++ b/Model/Tests/ModelTests/PlayerTests.swift @@ -0,0 +1,92 @@ +// +// File.swift +// +// +// Created by Louis DUFOUR on 31/01/2024. +// + +import Foundation +import Model +import XCTest + +/* +// Mocks et Stubs +class MockBoard: Board { + // Implémentez les méthodes nécessaires +} + +class MockRules: VerySimpleRules { + var mockMoves: [Move] = [] + + func getMoves(board: Board, owner: Owner) -> [Move] { + return mockMoves + } +} + +class MockMove: Move { + // Implémentez les détails nécessaires +} + +// Tests +class PlayerTests: XCTestCase { + func testPlayerInitialization() { + let player = Player(name: "TestPlayer", id: .player1) + XCTAssertNotNil(player) + XCTAssertEqual(player.name, "TestPlayer") + // Plus d'assertions pour id + } +} + +class HumanPlayerTests: XCTestCase { + var mockBoard: MockBoard! + var mockRules: MockRules! + var mockMove: MockMove! + + override func setUp() { + super.setUp() + mockBoard = MockBoard() + mockRules = MockRules() + mockMove = MockMove() + } + + func testHumanPlayerInitialization() { + let humanPlayer = HumanPlayer(name: "Human", id: .player1, inputMethod: { _, _ in return self.mockMove }) + XCTAssertNotNil(humanPlayer) + XCTAssertEqual(humanPlayer.name, "Human") + } + + func testHumanPlayerChooseMove() { + let humanPlayer = HumanPlayer(name: "Human", id: .player1, inputMethod: { _, _ in return self.mockMove }) + let move = humanPlayer.chooseMove(board: mockBoard, rules: mockRules) + XCTAssertEqual(move, mockMove) + } +} + +class RandomPlayerTests: XCTestCase { + var mockBoard: MockBoard! + var mockRules: MockRules! + var mockMove: MockMove! + + override func setUp() { + super.setUp() + mockBoard = MockBoard() + mockRules = MockRules() + mockMove = MockMove() + mockRules.mockMoves = [mockMove] + } + + + func testRandomPlayerInitialization() { + let randomPlayer = RandomPlayer(withName: "Random", andId: .player2) + XCTAssertNotNil(randomPlayer) + XCTAssertEqual(randomPlayer.name, "Random") + } + + func testRandomPlayerChooseMove() { + let randomPlayer = RandomPlayer(withName: "Random", andId: .player2) + let move = randomPlayer.chooseMove(board: mockBoard, rules: mockRules) + XCTAssertNotNil(move) + } +}*/ + + diff --git a/Model/Tests/ModelTests/VerySimpleRulesTests.swift b/Model/Tests/ModelTests/VerySimpleRulesTests.swift index 90337c0..980acc5 100644 --- a/Model/Tests/ModelTests/VerySimpleRulesTests.swift +++ b/Model/Tests/ModelTests/VerySimpleRulesTests.swift @@ -1,6 +1,21 @@ import XCTest @testable import Model class VerySimpleRulesTests: XCTestCase { + + var rules: VerySimpleRules! + var board: Board! + + override func setUp() { + super.setUp() + rules = VerySimpleRules() + board = VerySimpleRules.createBoard() + } + + override func tearDown() { + rules = nil + board = nil + super.tearDown() + } func testCreateBoard() { // Test que la fonction createBoard() retourne un plateau valide avec les dimensions attendues @@ -18,7 +33,84 @@ class VerySimpleRulesTests: XCTestCase { rules.historic.append(Move(owner: .player2, rowOrigin: 0, columnOrigin: 1, rowDestination: 0, columnDestination: 2)) XCTAssertEqual(rules.getNextPlayer(), .player1) } + + func testCheckBoardValid() { + // Assurez-vous que la méthode `checkBoard` ne lève pas d'exception pour un plateau valide + XCTAssertNoThrow(try VerySimpleRules.checkBoard(b: board)) + } + + func testCheckBoardInvalidDimensions() { + // Création d'un plateau avec des dimensions invalides (4x4 au lieu de 5x5) + var invalidCells = [[Cell]]() + + for _ in 0..<4 { + var rowCells = [Cell]() + for _ in 0..<4 { + // Créez des cellules basiques, les détails dépendent de votre implémentation de Cell + let cell = Cell(ofType: .jungle, ownedBy: .noOne, withPiece: nil) + rowCells.append(cell) + } + invalidCells.append(rowCells) + } + + let invalidBoard = Board(withGrid: invalidCells)! + XCTAssertThrowsError(try VerySimpleRules.checkBoard(b: invalidBoard)) + } + + func testGetMoves() { + // Supposons que pour une configuration de plateau spécifique, vous attendiez 3 mouvements possibles pour le joueur 1 + let expectedMoveCountForPlayer1 = 3 // Remplacez 3 par le nombre correct basé sur votre jeu + + // Test pour vérifier si getMoves retourne les bons mouvements pour le joueur 1 + let movesForPlayer1 = rules.getMoves(board: board, owner: .player1) + // XCTAssertEqual(movesForPlayer1.count, expectedMoveCountForPlayer1) + } + + func testIsMoveValid() { + // Test pour un mouvement valide + let validMove = Move(owner: .player1, rowOrigin: 0, columnOrigin: 0, rowDestination: 1, columnDestination: 0) + XCTAssertTrue(rules.isMoveValid(board: board, move: validMove)) + + // Test pour un mouvement invalide (par exemple, déplacement vers une case occupée par le même joueur) + let invalidMove = Move(owner: .player1, rowOrigin: 0, columnOrigin: 0, rowDestination: 0, columnDestination: 1) + XCTAssertFalse(rules.isMoveValid(board: board, move: invalidMove)) + } + + func testIsGameOver() { + // Assurez-vous que `board` est bien initialisé + guard let currentBoard = board else { + XCTFail("Board is not initialized") + return + } + + // Créez un mouvement qui simule une fin de partie + let winningMove = Move(owner: .player1, rowOrigin: 3, columnOrigin: 2, rowDestination: 4, columnDestination: 2) + + /* + // Appliquez ce mouvement au plateau + // Cette partie dépend de la façon dont votre jeu applique les mouvements + // Ici, un exemple générique où nous remplaçons simplement la pièce dans la cellule de destination + if let piece = currentBoard.grid[winningMove.rowOrigin][winningMove.columnOrigin].piece { + currentBoard.grid[winningMove.rowDestination][winningMove.columnDestination].piece = piece + currentBoard.grid[winningMove.rowOrigin][winningMove.columnOrigin].piece = nil + } + */ + + // Testez si `isGameOver` détecte correctement la fin de partie + let (isGameOver, result) = rules.isGameOver(board: currentBoard, lastMove: winningMove) + + XCTAssertTrue(isGameOver) + // Vérifiez le résultat spécifique de la fin de partie + switch result { + case .winner(let winner, let winCondition): + XCTAssertEqual(winner, .player1) + XCTAssertEqual(winCondition, .denReached) + default: + XCTFail("Unexpected game over result") + } + } + static var allTests = [ ("testCreateBoard", testCreateBoard), ("testGetNextPlayer", testGetNextPlayer), diff --git a/ModelCov.xctestplan b/ModelCov.xctestplan new file mode 100644 index 0000000..7fcde02 --- /dev/null +++ b/ModelCov.xctestplan @@ -0,0 +1,24 @@ +{ + "configurations" : [ + { + "id" : "117362A3-7E9A-409E-91DB-0965BE3D3808", + "name" : "Configuration 1", + "options" : { + + } + } + ], + "defaultOptions" : { + + }, + "testTargets" : [ + { + "target" : { + "containerPath" : "container:", + "identifier" : "ModelTests", + "name" : "ModelTests" + } + } + ], + "version" : 1 +} diff --git a/WorkSpaceDouShouQi.xcworkspace/contents.xcworkspacedata b/WorkSpaceDouShouQi.xcworkspace/contents.xcworkspacedata index e8da9c7..e87c729 100644 --- a/WorkSpaceDouShouQi.xcworkspace/contents.xcworkspacedata +++ b/WorkSpaceDouShouQi.xcworkspace/contents.xcworkspacedata @@ -10,4 +10,7 @@ + +