Merge pull request 'Tp2' (#3) from Tp2 into master

Reviewed-on: #3
pull/4/head
Louis DUFOUR 2 years ago
commit 5d173dc100

@ -58,7 +58,36 @@ let initialBoardConfiguration: [[Cell]] = [
if let board = Board(withGrid: initialBoardConfiguration) { if let board = Board(withGrid: initialBoardConfiguration) {
// Afficher le plateau de jeu // Afficher le plateau de jeu
print(board.display()) print(board)
} else {
print("Erreur lors de l'initialisation du plateau de jeu.")
}
// Initialisez un Board avec cette configuration
if var board = Board(withGrid: initialBoardConfiguration) {
print("Plateau initial:")
print(board) // Affichez l'état initial du plateau
// Testez countPieces(of:)
let player1PieceCount = board.countPieces(of: .player1)
print("Nombre de pièces pour le Joueur 1: \(player1PieceCount)")
let player2PieceCount = board.countPieces(of: .player2)
print("Nombre de pièces pour le Joueur 2: \(player2PieceCount)")
// Testez countPieces()
let (countPlayer1, countPlayer2) = board.countPieces()
print("Comptage total - Joueur 1: \(countPlayer1), Joueur 2: \(countPlayer2)")
// Testez removePiece(atRow:andColumn:)
let removeResult = board.removePiece(atRow: 0, andColumn: 0)
print("Résultat de la suppression : \(removeResult)")
print(board) // Affichez le plateau après suppression
// Testez insert(piece:atRow:andColumn:)
let insertResult = board.insert(piece: Piece(withOwner: .player1, andAnimal: .lion), atRow: 0, andColumn: 0)
print("Résultat de l'insertion : \(insertResult)")
print(board) // Affichez le plateau après insertion
} else { } else {
print("Erreur lors de l'initialisation du plateau de jeu.") print("Erreur lors de l'initialisation du plateau de jeu.")
} }

@ -9,16 +9,20 @@ import Foundation
import Model import Model
public extension Board {
func display() { extension Board: CustomStringConvertible {
public var description: String {
var description = ""
for row in grid { for row in grid {
for cell in row { for cell in row {
if let piece = cell.piece { if let piece = cell.piece {
print(cell.cellType.symbol + piece.owner.symbol + piece.animal.symbol, terminator: " ")} description += cell.cellType.symbol + piece.owner.symbol + piece.animal.symbol + " "}
else { else {
print(cell.cellType.symbol, terminator: " ")} description += cell.cellType.symbol + " "}
} }
print() description += "\n"
} }
return description
} }
} }

@ -0,0 +1,77 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1420"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "Model"
BuildableName = "Model"
BlueprintName = "Model"
ReferencedContainer = "container:">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
<TestableReference
skipped = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "ModelTests"
BuildableName = "ModelTests"
BlueprintName = "ModelTests"
ReferencedContainer = "container:">
</BuildableReference>
</TestableReference>
</Testables>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "Model"
BuildableName = "Model"
BlueprintName = "Model"
ReferencedContainer = "container:">
</BuildableReference>
</MacroExpansion>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>

@ -0,0 +1,58 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1420"
version = "1.7">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<TestPlans>
<TestPlanReference
reference = "container:Tests/ModelTests/ModelTests copy.xctestplan"
default = "YES">
</TestPlanReference>
</TestPlans>
<Testables>
<TestableReference
skipped = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "ModelTests"
BuildableName = "ModelTests"
BlueprintName = "ModelTests"
ReferencedContainer = "container:">
</BuildableReference>
</TestableReference>
</Testables>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>

@ -7,7 +7,7 @@
import Foundation import Foundation
public enum Animal: String { case rat, cat, dog, wolf, leopard, tiger, lion, elephant public enum Animal : CustomStringConvertible { case rat, cat, dog, wolf, leopard, tiger, lion, elephant
public var description: String { public var description: String {
switch self { switch self {

@ -7,10 +7,10 @@
import Foundation import Foundation
public struct Board { public struct Board : CustomStringConvertible {
let nbRows: Int public let nbRows: Int
let nbColumns: Int public let nbColumns: Int
public var grid: [[Cell]] public private(set) var grid: [[Cell]]
public init?(withGrid grid: [[Cell]]) { public init?(withGrid grid: [[Cell]]) {
guard let firstRowLength = grid.first?.count, grid.allSatisfy({ $0.count == firstRowLength }) else { guard let firstRowLength = grid.first?.count, grid.allSatisfy({ $0.count == firstRowLength }) else {
@ -22,13 +22,49 @@ public struct Board {
self.grid=grid self.grid=grid
} }
func getCell(atRow row: Int, column: Int) -> Cell? { public func getCell(atRow row: Int, column: Int) -> Cell? {
guard row >= 0, row < nbRows, column >= 0, column < nbColumns else { guard row >= 0, row < nbRows, column >= 0, column < nbColumns else {
return nil return nil
} }
return grid[row][column] return grid[row][column]
} }
public func countPieces(of owner: Owner) -> Int {
return grid.flatMap({ $0 }).filter({ $0.piece?.owner == owner }).count
}
public func countPieces() -> (player1: Int, player2: Int) {
let player1Count = countPieces(of: .player1)
let player2Count = countPieces(of: .player2)
return (player1Count, player2Count)
}
public mutating func insert(piece: Piece, atRow row: Int, andColumn column: Int) -> BoardResult {
guard row >= 0, row < nbRows, column >= 0, column < nbColumns else {
return .failed(reason: .outOfBounds)
}
if grid[row][column].piece == nil {
grid[row][column].piece = piece
return .ok
} else {
return .failed(reason: .cellNotEmpty)
}
}
public mutating func removePiece(atRow row: Int, andColumn column: Int) -> BoardResult {
guard row >= 0, row < nbRows, column >= 0, column < nbColumns else {
return .failed(reason: .outOfBounds)
}
if grid[row][column].piece != nil {
grid[row][column].piece = nil
return .ok
} else {
return .failed(reason: .cellEmpty)
}
}
public var description: String { public var description: String {
var boardDescription = "" var boardDescription = ""
for row in grid { for row in grid {

@ -0,0 +1,15 @@
//
// File.swift
//
//
// Created by Louis DUFOUR on 17/01/2024.
//
import Foundation
public enum BoardFailingReason {
case outOfBounds
case cellNotEmpty
case cellEmpty
case unknown
}

@ -0,0 +1,14 @@
//
// File.swift
//
//
// Created by Louis DUFOUR on 17/01/2024.
//
import Foundation
public enum BoardResult : Equatable {
case ok
case failed(reason: BoardFailingReason)
}

@ -7,7 +7,7 @@
import Foundation import Foundation
public struct Cell { public struct Cell : CustomStringConvertible {
public let cellType: CellType public let cellType: CellType
public var initialOwner: Owner public var initialOwner: Owner
public var piece: Piece? public var piece: Piece?
@ -19,10 +19,6 @@ public struct Cell {
} }
public var description: String { public var description: String {
var pieceDescription = "nil"
if let piece = piece {
pieceDescription = piece.description
}
return "Cell(type: (cellType), owner: (initialOwner), piece: (pieceDescription))" return "Cell(type: (cellType), owner: (initialOwner), piece: (pieceDescription))"
} }
} }

@ -7,7 +7,7 @@
import Foundation import Foundation
public enum CellType { public enum CellType : CustomStringConvertible {
case unknown, jungle, water, trap, den case unknown, jungle, water, trap, den
public var description: String { public var description: String {

@ -7,7 +7,7 @@
import Foundation import Foundation
public enum Owner { public enum Owner : CustomStringConvertible {
case noOne, player1, player2 case noOne, player1, player2
public var description: String { public var description: String {

@ -7,7 +7,7 @@
import Foundation import Foundation
public struct Piece { public struct Piece : CustomStringConvertible{
public let owner: Owner public let owner: Owner
public let animal: Animal public let animal: Animal

@ -0,0 +1,24 @@
{
"configurations" : [
{
"id" : "FDE4F17C-2211-4B72-BFD6-0E54DA99D1CC",
"name" : "Configuration 1",
"options" : {
}
}
],
"defaultOptions" : {
},
"testTargets" : [
{
"target" : {
"containerPath" : "container:",
"identifier" : "ModelTests",
"name" : "ModelTests"
}
}
],
"version" : 1
}

@ -1,13 +1,244 @@
import XCTest import XCTest
@testable import Model @testable import Model
class BoardTests: XCTestCase {
/* // Initialisez un Board de test avec une configuration de test
final class ModelTests: XCTestCase { var testBoard: Board!
func testExample() throws {
// This is an example of a functional test case. override func setUp() {
// Use XCTAssert and related functions to verify your tests produce the correct super.setUp()
// results. // Initialisez un Board avec une configuration de test
XCTAssertEqual(Model().text, "Hello, World!") testBoard = Board(withGrid: initialTestConfiguration)
}
override func tearDown() {
// Nettoyez après chaque test si nécessaire
testBoard = nil
super.tearDown()
}
// Testez l'initialisateur de Board
func testBoardInitializer() {
XCTAssertNotNil(testBoard) // Vérifiez que le Board a été initialisé avec succès
// Vérifiez que la taille du plateau correspond à la configuration initiale
XCTAssertEqual(testBoard.nbRows, initialTestConfiguration.count)
XCTAssertEqual(testBoard.nbColumns, initialTestConfiguration[0].count)
// Ajoutez d'autres vérifications si nécessaire pour vous assurer que le plateau a été initialisé correctement
}
// Testez countPieces(of:)
func testCountPiecesOfPlayer() {
XCTAssertEqual(testBoard.countPieces(of: .player1), expectedPlayer1PieceCount)
XCTAssertEqual(testBoard.countPieces(of: .player2), expectedPlayer2PieceCount)
}
// Testez countPieces()
func testCountTotalPieces() {
let (countPlayer1, countPlayer2) = testBoard.countPieces()
XCTAssertEqual(countPlayer1, expectedPlayer1PieceCount)
XCTAssertEqual(countPlayer2, expectedPlayer2PieceCount)
}
// Testez removePiece(atRow:andColumn:)
func testRemovePiece() {
let initialCell = testBoard.getCell(atRow: 0, column: 0)
XCTAssertNotNil(initialCell?.piece)
let result = testBoard.removePiece(atRow: 0, andColumn: 0)
XCTAssertEqual(result, .ok)
// Vérifiez que la pièce a été supprimée correctement
let removedCell = testBoard.getCell(atRow: 0, column: 0)
XCTAssertNil(removedCell?.piece)
}
// Testez insert(piece:atRow:andColumn:)
func testInsertPiece() {
// Supprimez toute pièce existante dans la case cible (si elle existe)
let initialCell = testBoard.getCell(atRow: 0, column: 0)
if initialCell?.piece != nil {
let removeResult = testBoard.removePiece(atRow: 0, andColumn: 0)
XCTAssertEqual(removeResult, .ok)
}
// Insérez une nouvelle pièce dans la case
let insertResult = testBoard.insert(piece: Piece(withOwner: .player1, andAnimal: .lion), atRow: 0, andColumn: 0)
XCTAssertEqual(insertResult, .ok)
// Vérifiez que la pièce a été insérée correctement
let cell = testBoard.getCell(atRow: 0, column: 0)
XCTAssertNotNil(cell?.piece)
XCTAssertEqual(cell?.piece?.owner, .player1)
XCTAssertEqual(cell?.piece?.animal, .lion)
} }
// Exemple de données de test pour la configuration initiale
let initialTestConfiguration: [[Cell]] = [
// Ligne 1
[Cell(ofType: .jungle, withPiece: Piece(withOwner: .player1, andAnimal: .lion)),
Cell(ofType: .jungle), Cell(ofType: .trap), Cell(ofType: .den), Cell(ofType: .trap),
Cell(ofType: .jungle), Cell(ofType: .jungle, withPiece: Piece(withOwner: .player1, andAnimal: .tiger))],
// Ligne 2
[Cell(ofType: .jungle), Cell(ofType: .jungle, withPiece: Piece(withOwner: .player1, andAnimal: .dog)),
Cell(ofType: .jungle), Cell(ofType: .trap), Cell(ofType: .jungle),
Cell(ofType: .jungle, withPiece: Piece(withOwner: .player1, andAnimal: .cat)), Cell(ofType: .jungle)],
// Ligne 3
[Cell(ofType: .jungle, withPiece: Piece(withOwner: .player1, andAnimal: .rat)),
Cell(ofType: .jungle), Cell(ofType: .jungle, withPiece: Piece(withOwner: .player1, andAnimal: .leopard)),
Cell(ofType: .jungle), Cell(ofType: .jungle, withPiece: Piece(withOwner: .player1, andAnimal: .wolf)),
Cell(ofType: .jungle), Cell(ofType: .jungle, withPiece: Piece(withOwner: .player1, andAnimal: .elephant))],
// Lignes 4 à 7 (Eau et Jungle)
[Cell(ofType: .jungle), Cell(ofType: .water), Cell(ofType: .water),
Cell(ofType: .jungle), Cell(ofType: .water), Cell(ofType: .water), Cell(ofType: .jungle)],
[Cell(ofType: .jungle), Cell(ofType: .water), Cell(ofType: .water),
Cell(ofType: .jungle), Cell(ofType: .water), Cell(ofType: .water), Cell(ofType: .jungle)],
[Cell(ofType: .jungle), Cell(ofType: .water), Cell(ofType: .water),
Cell(ofType: .jungle), Cell(ofType: .water), Cell(ofType: .water), Cell(ofType: .jungle)],
[Cell(ofType: .jungle), Cell(ofType: .water), Cell(ofType: .water),
Cell(ofType: .jungle), Cell(ofType: .water), Cell(ofType: .water), Cell(ofType: .jungle)],
// Ligne 8
[Cell(ofType: .jungle, withPiece: Piece(withOwner: .player2, andAnimal: .elephant)),
Cell(ofType: .jungle), Cell(ofType: .jungle, withPiece: Piece(withOwner: .player2, andAnimal: .wolf)),
Cell(ofType: .jungle), Cell(ofType: .jungle, withPiece: Piece(withOwner: .player2, andAnimal: .leopard)),
Cell(ofType: .jungle), Cell(ofType: .jungle, withPiece: Piece(withOwner: .player2, andAnimal: .rat))],
// Ligne 9
[Cell(ofType: .jungle), Cell(ofType: .jungle, withPiece: Piece(withOwner: .player2, andAnimal: .cat)),
Cell(ofType: .jungle), Cell(ofType: .trap), Cell(ofType: .jungle),
Cell(ofType: .jungle, withPiece: Piece(withOwner: .player2, andAnimal: .dog)), Cell(ofType: .jungle)],
// Ligne 10
[Cell(ofType: .jungle, withPiece: Piece(withOwner: .player2, andAnimal: .tiger)),
Cell(ofType: .jungle), Cell(ofType: .trap), Cell(ofType: .den), Cell(ofType: .trap),
Cell(ofType: .jungle), Cell(ofType: .jungle, withPiece: Piece(withOwner: .player2, andAnimal: .lion))]
]
let expectedPlayer1PieceCount = 8 // Le nombre attendu de pièces pour le joueur 1
let expectedPlayer2PieceCount = 8 // Le nombre attendu de pièces pour le joueur 2
}
class BoardPerformanceTests: XCTestCase {
// Initialisez un Board de test avec une configuration de test
var testBoard: Board!
override func setUp() {
super.setUp()
// Initialisez un Board avec une configuration de test
testBoard = Board(withGrid: initialTestConfiguration)
}
override func tearDown() {
// Nettoyez après chaque test si nécessaire
testBoard = nil
super.tearDown()
}
// Test de performance pour countPieces(of:)
func testPerformanceCountPiecesOfPlayer() {
self.measure {
for _ in 0..<1000 { // Exécutez le test 1000 fois pour mesurer les performances
let _ = testBoard.countPieces(of: .player1)
}
}
}
// Test de performance pour countPieces()
func testPerformanceCountTotalPieces() {
self.measure {
for _ in 0..<1000 { // Exécutez le test 1000 fois pour mesurer les performances
let _ = testBoard.countPieces()
}
}
}
// Test de performance pour insert(piece:atRow:andColumn:)
func testPerformanceInsertPiece() {
let pieceToInsert = Piece(withOwner: .player1, andAnimal: .lion)
self.measure {
for _ in 0..<1000 { // Exécutez le test 1000 fois pour mesurer les performances
let _ = testBoard.insert(piece: pieceToInsert, atRow: 0, andColumn: 0)
// Nettoyez après chaque itération pour réinitialiser l'état du plateau
let _ = testBoard.removePiece(atRow: 0, andColumn: 0)
}
}
}
// Test de performance pour removePiece(atRow:andColumn:)
func testPerformanceRemovePiece() {
let pieceToRemove = Piece(withOwner: .player1, andAnimal: .lion)
let _ = testBoard.insert(piece: pieceToRemove, atRow: 0, andColumn: 0)
self.measure {
for _ in 0..<1000 { // Exécutez le test 1000 fois pour mesurer les performances
let _ = testBoard.removePiece(atRow: 0, andColumn: 0)
// Réinsérez la pièce après chaque itération pour réinitialiser l'état du plateau
let _ = testBoard.insert(piece: pieceToRemove, atRow: 0, andColumn: 0)
}
}
}
// Test de performance pour l'initialisateur de Board
func testPerformanceInitializeBoard() {
self.measure {
for _ in 0..<1000 { // Exécutez le test 1000 fois pour mesurer les performances
_ = Board(withGrid: initialTestConfiguration)
}
}
}
// Exemple de données de test pour la configuration initiale
let initialTestConfiguration: [[Cell]] = [
// Ligne 1
[Cell(ofType: .jungle, withPiece: Piece(withOwner: .player1, andAnimal: .lion)),
Cell(ofType: .jungle), Cell(ofType: .trap), Cell(ofType: .den), Cell(ofType: .trap),
Cell(ofType: .jungle), Cell(ofType: .jungle, withPiece: Piece(withOwner: .player1, andAnimal: .tiger))],
// Ligne 2
[Cell(ofType: .jungle), Cell(ofType: .jungle, withPiece: Piece(withOwner: .player1, andAnimal: .dog)),
Cell(ofType: .jungle), Cell(ofType: .trap), Cell(ofType: .jungle),
Cell(ofType: .jungle, withPiece: Piece(withOwner: .player1, andAnimal: .cat)), Cell(ofType: .jungle)],
// Ligne 3
[Cell(ofType: .jungle, withPiece: Piece(withOwner: .player1, andAnimal: .rat)),
Cell(ofType: .jungle), Cell(ofType: .jungle, withPiece: Piece(withOwner: .player1, andAnimal: .leopard)),
Cell(ofType: .jungle), Cell(ofType: .jungle, withPiece: Piece(withOwner: .player1, andAnimal: .wolf)),
Cell(ofType: .jungle), Cell(ofType: .jungle, withPiece: Piece(withOwner: .player1, andAnimal: .elephant))],
// Lignes 4 à 7 (Eau et Jungle)
[Cell(ofType: .jungle), Cell(ofType: .water), Cell(ofType: .water),
Cell(ofType: .jungle), Cell(ofType: .water), Cell(ofType: .water), Cell(ofType: .jungle)],
[Cell(ofType: .jungle), Cell(ofType: .water), Cell(ofType: .water),
Cell(ofType: .jungle), Cell(ofType: .water), Cell(ofType: .water), Cell(ofType: .jungle)],
[Cell(ofType: .jungle), Cell(ofType: .water), Cell(ofType: .water),
Cell(ofType: .jungle), Cell(ofType: .water), Cell(ofType: .water), Cell(ofType: .jungle)],
[Cell(ofType: .jungle), Cell(ofType: .water), Cell(ofType: .water),
Cell(ofType: .jungle), Cell(ofType: .water), Cell(ofType: .water), Cell(ofType: .jungle)],
// Ligne 8
[Cell(ofType: .jungle, withPiece: Piece(withOwner: .player2, andAnimal: .elephant)),
Cell(ofType: .jungle), Cell(ofType: .jungle, withPiece: Piece(withOwner: .player2, andAnimal: .wolf)),
Cell(ofType: .jungle), Cell(ofType: .jungle, withPiece: Piece(withOwner: .player2, andAnimal: .leopard)),
Cell(ofType: .jungle), Cell(ofType: .jungle, withPiece: Piece(withOwner: .player2, andAnimal: .rat))],
// Ligne 9
[Cell(ofType: .jungle), Cell(ofType: .jungle, withPiece: Piece(withOwner: .player2, andAnimal: .cat)),
Cell(ofType: .jungle), Cell(ofType: .trap), Cell(ofType: .jungle),
Cell(ofType: .jungle, withPiece: Piece(withOwner: .player2, andAnimal: .dog)), Cell(ofType: .jungle)],
// Ligne 10
[Cell(ofType: .jungle, withPiece: Piece(withOwner: .player2, andAnimal: .tiger)),
Cell(ofType: .jungle), Cell(ofType: .trap), Cell(ofType: .den), Cell(ofType: .trap),
Cell(ofType: .jungle), Cell(ofType: .jungle, withPiece: Piece(withOwner: .player2, andAnimal: .lion))]
]
} }
*/

@ -4,6 +4,9 @@
## Introduction ## Introduction
Le projet DouShouQi en Swift est une implémentation console du jeu de plateau DouShouQi. Le projet DouShouQi en Swift est une implémentation console du jeu de plateau DouShouQi.
## Correction
Le commit à prendre en compte pour ce Tp2 est : 8e178e86b1
## Prérequis ## Prérequis
- **Système d'exploitation**: macOS Ventura 13.1 - **Système d'exploitation**: macOS Ventura 13.1
- **Logiciel**: Xcode version 14.2 - **Logiciel**: Xcode version 14.2

Loading…
Cancel
Save