From 43d8ff97bf66b8f3b4ea044d53f3ee9efd16e930 Mon Sep 17 00:00:00 2001 From: meatball Date: Thu, 26 Dec 2024 23:04:23 +0100 Subject: [PATCH 1/5] Update Swift tools version to 6.0 and add new Position struct for saddle points exercise --- .../.docs/instructions.append.md | 11 + .../complex-numbers/.docs/instructions.md | 107 +++- .../ComplexNumbersExample.swift | 73 +-- .../complex-numbers/.meta/config.json | 3 +- .../complex-numbers/.meta/template.swift | 72 +++ .../practice/complex-numbers/.meta/tests.toml | 27 + .../practice/complex-numbers/Package.swift | 13 +- .../ComplexNumbersTests.swift | 589 ++++++++++-------- .../.meta/Sources/Poker/PokerExample.swift | 557 +++++++---------- exercises/practice/poker/.meta/template.swift | 21 + exercises/practice/poker/.meta/tests.toml | 39 +- exercises/practice/poker/Package.swift | 32 +- .../poker/Tests/PokerTests/PokerTests.swift | 586 +++++++++-------- .../.meta/Sources/SaddlePoints/Position.swift | 8 + .../SaddlePoints/SaddlePointsExample.swift | 56 +- .../practice/saddle-points/.meta/config.json | 3 + .../saddle-points/.meta/template.swift | 31 + .../practice/saddle-points/Package.swift | 2 +- .../Sources/SaddlePoints/Position.swift | 8 + .../SaddlePointsTests/SaddlePointsTests.swift | 151 +++-- .../Sources/Generator/generator-plugins.swift | 20 + 21 files changed, 1360 insertions(+), 1049 deletions(-) create mode 100644 exercises/practice/complex-numbers/.docs/instructions.append.md create mode 100644 exercises/practice/complex-numbers/.meta/template.swift create mode 100644 exercises/practice/poker/.meta/template.swift create mode 100644 exercises/practice/saddle-points/.meta/Sources/SaddlePoints/Position.swift create mode 100644 exercises/practice/saddle-points/.meta/template.swift create mode 100644 exercises/practice/saddle-points/Sources/SaddlePoints/Position.swift diff --git a/exercises/practice/complex-numbers/.docs/instructions.append.md b/exercises/practice/complex-numbers/.docs/instructions.append.md new file mode 100644 index 000000000..91e07b0d0 --- /dev/null +++ b/exercises/practice/complex-numbers/.docs/instructions.append.md @@ -0,0 +1,11 @@ +# Append + +You will have to implement your own equality operator for the `ComplexNumber` object. +This will pose the challenge of comparing two floating point numbers. +It might be useful to use the method `isApproximatelyEqual(to:absoluteTolerance:)` which can be found in the [Numerics][swift-numberics] library. +With a given tolerance of `0.00001` should be enough to pass the tests. +The library is already imported in the project so it is just to import it in your file. + +You are aLso free to implement your own method to compare the two complex numbers. + +[swift-numberics]: https://github.com/apple/swift-numerics diff --git a/exercises/practice/complex-numbers/.docs/instructions.md b/exercises/practice/complex-numbers/.docs/instructions.md index 50b19aedf..2b8a7a49d 100644 --- a/exercises/practice/complex-numbers/.docs/instructions.md +++ b/exercises/practice/complex-numbers/.docs/instructions.md @@ -1,29 +1,100 @@ # Instructions -A complex number is a number in the form `a + b * i` where `a` and `b` are real and `i` satisfies `i^2 = -1`. +A **complex number** is expressed in the form `z = a + b * i`, where: -`a` is called the real part and `b` is called the imaginary part of `z`. -The conjugate of the number `a + b * i` is the number `a - b * i`. -The absolute value of a complex number `z = a + b * i` is a real number `|z| = sqrt(a^2 + b^2)`. The square of the absolute value `|z|^2` is the result of multiplication of `z` by its complex conjugate. +- `a` is the **real part** (a real number), -The sum/difference of two complex numbers involves adding/subtracting their real and imaginary parts separately: -`(a + i * b) + (c + i * d) = (a + c) + (b + d) * i`, -`(a + i * b) - (c + i * d) = (a - c) + (b - d) * i`. +- `b` is the **imaginary part** (also a real number), and -Multiplication result is by definition -`(a + i * b) * (c + i * d) = (a * c - b * d) + (b * c + a * d) * i`. +- `i` is the **imaginary unit** satisfying `i^2 = -1`. -The reciprocal of a non-zero complex number is -`1 / (a + i * b) = a/(a^2 + b^2) - b/(a^2 + b^2) * i`. +## Operations on Complex Numbers -Dividing a complex number `a + i * b` by another `c + i * d` gives: -`(a + i * b) / (c + i * d) = (a * c + b * d)/(c^2 + d^2) + (b * c - a * d)/(c^2 + d^2) * i`. +### Conjugate -Raising e to a complex exponent can be expressed as `e^(a + i * b) = e^a * e^(i * b)`, the last term of which is given by Euler's formula `e^(i * b) = cos(b) + i * sin(b)`. +The conjugate of the complex number `z = a + b * i` is given by: -Implement the following operations: +```text +zc = a - b * i +``` -- addition, subtraction, multiplication and division of two complex numbers, -- conjugate, absolute value, exponent of a given complex number. +### Absolute Value -Assume the programming language you are using does not have an implementation of complex numbers. +The absolute value (or modulus) of `z` is defined as: + +```text +|z| = sqrt(a^2 + b^2) +``` + +The square of the absolute value is computed as the product of `z` and its conjugate `zc`: + +```text +|z|^2 = z * zc = a^2 + b^2 +``` + +### Addition + +The sum of two complex numbers `z1 = a + b * i` and `z2 = c + d * i` is computed by adding their real and imaginary parts separately: + +```text +z1 + z2 = (a + b * i) + (c + d * i) + = (a + c) + (b + d) * i +``` + +### Subtraction + +The difference of two complex numbers is obtained by subtracting their respective parts: + +```text +z1 - z2 = (a + b * i) - (c + d * i) + = (a - c) + (b - d) * i +``` + +### Multiplication + +The product of two complex numbers is defined as: + +```text +z1 * z2 = (a + b * i) * (c + d * i) + = (a * c - b * d) + (b * c + a * d) * i +``` + +### Reciprocal + +The reciprocal of a non-zero complex number is given by: + +```text +1 / z = 1 / (a + b * i) + = a / (a^2 + b^2) - b / (a^2 + b^2) * i +``` + +### Division + +The division of one complex number by another is given by: + +```text +z1 / z2 = z1 * (1 / z2) + = (a + b * i) / (c + d * i) + = (a * c + b * d) / (c^2 + d^2) + (b * c - a * d) / (c^2 + d^2) * i +``` + +### Exponentiation + +Raising _e_ (the base of the natural logarithm) to a complex exponent can be expressed using Euler's formula: + +```text +e^(a + b * i) = e^a * e^(b * i) + = e^a * (cos(b) + i * sin(b)) +``` + +## Implementation Requirements + +Given that you should not use built-in support for complex numbers, implement the following operations: + +- **addition** of two complex numbers +- **subtraction** of two complex numbers +- **multiplication** of two complex numbers +- **division** of two complex numbers +- **conjugate** of a complex number +- **absolute value** of a complex number +- **exponentiation** of _e_ (the base of the natural logarithm) to a complex number diff --git a/exercises/practice/complex-numbers/.meta/Sources/ComplexNumbers/ComplexNumbersExample.swift b/exercises/practice/complex-numbers/.meta/Sources/ComplexNumbers/ComplexNumbersExample.swift index 8b0548b21..e5a3d23f6 100644 --- a/exercises/practice/complex-numbers/.meta/Sources/ComplexNumbers/ComplexNumbersExample.swift +++ b/exercises/practice/complex-numbers/.meta/Sources/ComplexNumbers/ComplexNumbersExample.swift @@ -1,66 +1,51 @@ import Foundation +import Numerics -struct ComplexNumber { +struct ComplexNumbers: Equatable { - var realComponent: Double + var real: Double + var imaginary: Double - var imaginaryComponent: Double - - func getRealComponent() -> Double { - - return self.realComponent + init(realComponent: Double, imaginaryComponent: Double? = 0) { + real = realComponent + imaginary = imaginaryComponent ?? 0 } - func getImaginaryComponent() -> Double { - - return self.imaginaryComponent + func add(complexNumber: ComplexNumbers) -> ComplexNumbers { + ComplexNumbers(realComponent: real + complexNumber.real, imaginaryComponent: imaginary + complexNumber.imaginary) } - func add(complexNumber: ComplexNumber) -> ComplexNumber { - - return ComplexNumber(realComponent: self.realComponent + complexNumber.realComponent, imaginaryComponent: self.imaginaryComponent + complexNumber.imaginaryComponent) + func sub(complexNumber: ComplexNumbers) -> ComplexNumbers { + ComplexNumbers(realComponent: real - complexNumber.real, imaginaryComponent: imaginary - complexNumber.imaginary) } - func subtract(complexNumber: ComplexNumber) -> ComplexNumber { - - return ComplexNumber(realComponent: self.realComponent - complexNumber.realComponent, imaginaryComponent: self.imaginaryComponent - complexNumber.imaginaryComponent) + func mul(complexNumber: ComplexNumbers) -> ComplexNumbers { + ComplexNumbers(realComponent: real * complexNumber.real - imaginary * complexNumber.imaginary, imaginaryComponent: real * complexNumber.imaginary + imaginary * complexNumber.real) } - func multiply(complexNumber: ComplexNumber) -> ComplexNumber { - - return ComplexNumber(realComponent: self.realComponent * complexNumber.realComponent - self.imaginaryComponent * complexNumber.imaginaryComponent, imaginaryComponent: self.imaginaryComponent * complexNumber.realComponent + self.realComponent * complexNumber.imaginaryComponent) + func div(complexNumber: ComplexNumbers) -> ComplexNumbers { + let denominator = complexNumber.real * complexNumber.real + complexNumber.imaginary * complexNumber.imaginary + let realComponent = (real * complexNumber.real + imaginary * complexNumber.imaginary) / denominator + let imaginaryComponent = (imaginary * complexNumber.real - real * complexNumber.imaginary) / denominator + return ComplexNumbers(realComponent: realComponent, imaginaryComponent: imaginaryComponent) } - func divide(complexNumber: ComplexNumber) -> ComplexNumber { - - let amplitudeOfComplexNumber = (complexNumber.realComponent * complexNumber.realComponent) + (complexNumber.imaginaryComponent * complexNumber.imaginaryComponent) - - let realPartOfQuotient = (self.realComponent * complexNumber.realComponent + self.imaginaryComponent * complexNumber.imaginaryComponent) / amplitudeOfComplexNumber - - let imaginaryPartOfQuotient = (self.imaginaryComponent * complexNumber.realComponent - self.realComponent * self.realComponent * complexNumber.imaginaryComponent) / amplitudeOfComplexNumber - - return ComplexNumber(realComponent: realPartOfQuotient, imaginaryComponent: imaginaryPartOfQuotient) + func absolute() -> Double { + sqrt(Double(real * real + imaginary * imaginary)) } - func conjugate() -> ComplexNumber { - - return ComplexNumber(realComponent: self.realComponent, imaginaryComponent: (-1 * self.imaginaryComponent)) + func conjugate() -> ComplexNumbers { + ComplexNumbers(realComponent: real, imaginaryComponent: -imaginary) } - func absolute() -> Double { - - return sqrt(pow(self.realComponent, 2.0) + pow(self.imaginaryComponent, 2.0)) + func exponent() -> ComplexNumbers { + let expReal = exp(Double(real)) * cos(Double(imaginary)) + let expImaginary = exp(Double(real)) * sin(Double(imaginary)) + return ComplexNumbers(realComponent: expReal, imaginaryComponent: expImaginary) } - func exponent() -> ComplexNumber { - - let realPartOfResult = cos(self.imaginaryComponent) - let imaginaryPartOfResult = sin(self.imaginaryComponent) - let factor = exp(self.realComponent) - - return ComplexNumber(realComponent: realPartOfResult * factor, imaginaryComponent: imaginaryPartOfResult * factor) - + static func == (lhs: ComplexNumbers, rhs: ComplexNumbers) -> Bool { + lhs.real.isApproximatelyEqual(to: rhs.real, absoluteTolerance: 0.0001) && lhs.imaginary.isApproximatelyEqual(to: rhs.imaginary, absoluteTolerance: 0.0001) } - -} +} \ No newline at end of file diff --git a/exercises/practice/complex-numbers/.meta/config.json b/exercises/practice/complex-numbers/.meta/config.json index 49fb11649..bbb1b3e7a 100644 --- a/exercises/practice/complex-numbers/.meta/config.json +++ b/exercises/practice/complex-numbers/.meta/config.json @@ -1,6 +1,7 @@ { "authors": [ - "AlwynC" + "AlwynC", + "meatball133" ], "contributors": [ "bhargavg", diff --git a/exercises/practice/complex-numbers/.meta/template.swift b/exercises/practice/complex-numbers/.meta/template.swift new file mode 100644 index 000000000..444cc2a65 --- /dev/null +++ b/exercises/practice/complex-numbers/.meta/template.swift @@ -0,0 +1,72 @@ +import Testing +import Foundation + +@testable import {{exercise|camelCase}} + +let RUNALL = Bool(ProcessInfo.processInfo.environment["RUNALL", default: "false"]) ?? false + +@Suite struct {{exercise|camelCase}}Tests { + {% outer: for case in cases %} + {%- if case.cases %} + {%- for subCases in case.cases %} + {%- if subCases.cases %} + {%- for subSubCases in subCases.cases %} + @Test("{{subSubCases.description}}", .enabled(if: RUNALL)) + func test{{subSubCases.description |camelCase }}() { + let complexNumberOne = {{exercise|camelCase}}(realComponent: {{subSubCases.input.z1[0]}}, imaginaryComponent: {{subSubCases.input.z1[1]}}) + let complexNumberTwo = {{exercise|camelCase}}(realComponent: {{subSubCases.input.z2[0]}}, imaginaryComponent: {{subSubCases.input.z2[1]}}) + let result = complexNumberOne.{{subSubCases.property}}(complexNumber: complexNumberTwo) + let expected = {{exercise|camelCase}}(realComponent: {{subSubCases.expected[0]}}, imaginaryComponent: {{subSubCases.expected[1]}}) + #expect(expected == result) + } + {%- endfor %} + {%- else %} + {%- if forloop.outer.first and forloop.first %} + @Test("{{subCases.description}}") + {%- else %} + @Test("{{subCases.description}}", .enabled(if: RUNALL)) + {%- endif %} + func test{{subCases.description |camelCase }}() { + {%- if subCases.property == "real" or subCases.property == "imaginary" or subCases.property == "abs" or subCases.property == "conjugate" or subCases.property == "exp" %} + let complexNumber = {{exercise|camelCase}}(realComponent: {{subCases.input.z[0] | complexNumber}}, imaginaryComponent: {{subCases.input.z[1] | complexNumber}}) + {%- if subCases.property == "real" %} + #expect(complexNumber.real == {{subCases.expected}}) + {%- elif subCases.property == "imaginary" %} + #expect(complexNumber.imaginary == {{subCases.expected}}) + {%- elif subCases.property == "abs" %} + #expect(complexNumber.absolute() == {{subCases.expected}}) + {%- elif subCases.property == "conjugate" %} + let expected = {{exercise|camelCase}}(realComponent: {{subCases.expected[0]}}, imaginaryComponent: {{subCases.expected[1]}}) + #expect(complexNumber.conjugate() == expected) + {%- elif subCases.property == "exp" %} + let expected = {{exercise|camelCase}}(realComponent: {{subCases.expected[0] | complexNumber}}, imaginaryComponent: {{subCases.expected[1]}}) + #expect(complexNumber.exponent() == expected) + {%- elif subCases.property == "add" or subCases.property == "sub" or subCases.property == "mul" or subCases.property == "div" %} + {%- endif %} + {%- else %} + {%- if subCases.input.z1[0] %} + let complexNumberOne = {{exercise|camelCase}}(realComponent: {{subCases.input.z1[0]}}, imaginaryComponent: {{subCases.input.z1[1]}}) + let complexNumberTwo = {{exercise|camelCase}}(realComponent: {{subCases.input.z2}}, imaginaryComponent: nil) + {%- else %} + let complexNumberOne = {{exercise|camelCase}}(realComponent: {{subCases.input.z1}}, imaginaryComponent: nil) + let complexNumberTwo = {{exercise|camelCase}}(realComponent: {{subCases.input.z2[0]}}, imaginaryComponent: {{subCases.input.z2[1]}}) + {%- endif %} + let result = complexNumberOne.{{subCases.property}}(complexNumber: complexNumberTwo) + let expected = {{exercise|camelCase}}(realComponent: {{subCases.expected[0]}}, imaginaryComponent: {{subCases.expected[1]}}) + #expect(expected == result) + {%- endif %} + } + {%- endif %} + {% endfor -%} + {%- else %} + @Test("{{case.description}}", .enabled(if: RUNALL)) + func test{{case.description |camelCase }}() { + let complexNumberOne = {{exercise|camelCase}}(realComponent: {{case.input.z1[0]}}, imaginaryComponent: {{case.input.z1[1]}}) + let complexNumberTwo = {{exercise|camelCase}}(realComponent: {{case.input.z2[0]}}, imaginaryComponent: {{case.input.z2[1]}}) + let result = complexNumberOne.{{case.property}}(complexNumber: complexNumberTwo) + let expected = {{exercise|camelCase}}(realComponent: {{case.expected[0]}}, imaginaryComponent: {{case.expected[1]}}) + #expect(expected == result) + } + {%- endif %} + {% endfor -%} +} diff --git a/exercises/practice/complex-numbers/.meta/tests.toml b/exercises/practice/complex-numbers/.meta/tests.toml index 34af98758..dffb1f2a3 100644 --- a/exercises/practice/complex-numbers/.meta/tests.toml +++ b/exercises/practice/complex-numbers/.meta/tests.toml @@ -101,3 +101,30 @@ description = "Complex exponential function -> Exponential of a purely real numb [08eedacc-5a95-44fc-8789-1547b27a8702] description = "Complex exponential function -> Exponential of a number with real and imaginary part" + +[d2de4375-7537-479a-aa0e-d474f4f09859] +description = "Complex exponential function -> Exponential resulting in a number with real and imaginary part" + +[06d793bf-73bd-4b02-b015-3030b2c952ec] +description = "Operations between real numbers and complex numbers -> Add real number to complex number" + +[d77dbbdf-b8df-43f6-a58d-3acb96765328] +description = "Operations between real numbers and complex numbers -> Add complex number to real number" + +[20432c8e-8960-4c40-ba83-c9d910ff0a0f] +description = "Operations between real numbers and complex numbers -> Subtract real number from complex number" + +[b4b38c85-e1bf-437d-b04d-49bba6e55000] +description = "Operations between real numbers and complex numbers -> Subtract complex number from real number" + +[dabe1c8c-b8f4-44dd-879d-37d77c4d06bd] +description = "Operations between real numbers and complex numbers -> Multiply complex number by real number" + +[6c81b8c8-9851-46f0-9de5-d96d314c3a28] +description = "Operations between real numbers and complex numbers -> Multiply real number by complex number" + +[8a400f75-710e-4d0c-bcb4-5e5a00c78aa0] +description = "Operations between real numbers and complex numbers -> Divide complex number by real number" + +[9a867d1b-d736-4c41-a41e-90bd148e9d5e] +description = "Operations between real numbers and complex numbers -> Divide real number by complex number" diff --git a/exercises/practice/complex-numbers/Package.swift b/exercises/practice/complex-numbers/Package.swift index 1498214fe..987a426f2 100644 --- a/exercises/practice/complex-numbers/Package.swift +++ b/exercises/practice/complex-numbers/Package.swift @@ -1,4 +1,4 @@ -// swift-tools-version:5.3 +// swift-tools-version:6.0 import PackageDescription @@ -9,13 +9,18 @@ let package = Package( name: "ComplexNumbers", targets: ["ComplexNumbers"]), ], - dependencies: [], + dependencies: [ + .package(url: "https://github.com/apple/swift-numerics", from: "1.0.2"), + ], targets: [ .target( name: "ComplexNumbers", - dependencies: []), + dependencies: [ + .product(name: "Numerics", package: "swift-numerics"), + ]), .testTarget( name: "ComplexNumbersTests", - dependencies: ["ComplexNumbers"]), + dependencies: ["ComplexNumbers", + .product(name: "Numerics", package: "swift-numerics"),]), ] ) diff --git a/exercises/practice/complex-numbers/Tests/ComplexNumbersTests/ComplexNumbersTests.swift b/exercises/practice/complex-numbers/Tests/ComplexNumbersTests/ComplexNumbersTests.swift index e75e8071a..14c2ccab7 100644 --- a/exercises/practice/complex-numbers/Tests/ComplexNumbersTests/ComplexNumbersTests.swift +++ b/exercises/practice/complex-numbers/Tests/ComplexNumbersTests/ComplexNumbersTests.swift @@ -1,280 +1,317 @@ -import XCTest -@testable import ComplexNumbers - -class ComplexNumbersTests: XCTestCase { - - override func setUp() { - super.setUp() - // Put setup code here. This method is called before the invocation of each test method in the class. - } - - override func tearDown() { - // Put teardown code here. This method is called after the invocation of each test method in the class. - super.tearDown() - } - - func testRealPartOfPurelyRealNumber() { - - let input = ComplexNumber(realComponent: 1, imaginaryComponent: 0) - let expectedOutput = Double(1) - XCTAssertEqual(expectedOutput, input.getRealComponent()) - } - - func testRealPartOfPurelyImaginaryNumber() { - - let input = ComplexNumber(realComponent: 0, imaginaryComponent: 1) - let expectedOutput = Double(1) - XCTAssertEqual(expectedOutput, input.getImaginaryComponent()) - } - - func testRealPartOfNumberWithRealAndImaginary() { - - let input = ComplexNumber(realComponent: 1, imaginaryComponent: 2) - let expectedOutput = Double(1) - XCTAssertEqual(expectedOutput, input.getRealComponent()) - } - - func testImaginaryPartOfPurelyRealNumber() { - - let input = ComplexNumber(realComponent: 1, imaginaryComponent: 0) - let expectedOutput = Double(0) - XCTAssertEqual(expectedOutput, input.getImaginaryComponent()) - } - - func testImaginaryPartOfPurelyImaginaryNumber() { - - let input = ComplexNumber(realComponent: 0, imaginaryComponent: 1) - let expectedOutput = Double(1) - XCTAssertEqual(expectedOutput, input.getImaginaryComponent()) - } - - func testImaginaryPartOfNumberWithRealAndImaginary() { - - let input = ComplexNumber(realComponent: 1, imaginaryComponent: 2) - let expectedOutput = Double(2) - XCTAssertEqual(expectedOutput, input.getImaginaryComponent()) - } - - func testImaginaryUnit() { - - let multiplicand = ComplexNumber(realComponent: 0, imaginaryComponent: 1) - let multiplier = ComplexNumber(realComponent: 0, imaginaryComponent: 1) - let expectedProduct = ComplexNumber(realComponent: -1, imaginaryComponent: 0) - let actualProduct = multiplicand.multiply(complexNumber: multiplier) - XCTAssertEqual([expectedProduct.realComponent, expectedProduct.imaginaryComponent], [actualProduct.realComponent, actualProduct.imaginaryComponent]) - } - - func testAddPurelyRealNumbers() { - - let addend = ComplexNumber(realComponent: 1, imaginaryComponent: 0) - let augend = ComplexNumber(realComponent: 2, imaginaryComponent: 0) - let expectedSum = ComplexNumber(realComponent: 3, imaginaryComponent: 0) - let actualSum = ComplexNumber(realComponent: addend.add(complexNumber: augend).realComponent, imaginaryComponent: addend.add(complexNumber: augend).imaginaryComponent) - XCTAssertEqual([expectedSum.realComponent, expectedSum.imaginaryComponent], [actualSum.realComponent, actualSum.imaginaryComponent]) - } - - func testAddPurelyImaginaryNumbers() { - - let addend = ComplexNumber(realComponent: 0, imaginaryComponent: 1) - let augend = ComplexNumber(realComponent: 0, imaginaryComponent: 2) - let expectedSum = ComplexNumber(realComponent: 0, imaginaryComponent: 3) - let actualSum = addend.add(complexNumber: augend) - - XCTAssertEqual([expectedSum.realComponent, expectedSum.imaginaryComponent], [actualSum.realComponent, actualSum.imaginaryComponent]) - } - - func testAddNumbersWithRealAndImaginaryParts() { - - let addend = ComplexNumber(realComponent: 1, imaginaryComponent: 2) - let augend = ComplexNumber(realComponent: 3, imaginaryComponent: 4) - let expectedSum = ComplexNumber(realComponent: 4, imaginaryComponent: 6) - let actualSum = addend.add(complexNumber: augend) - - XCTAssertEqual([expectedSum.realComponent, expectedSum.imaginaryComponent], [actualSum.realComponent, actualSum.imaginaryComponent]) - } - - func testSubtractPurelyRealNumbers() { - - let subtrahend = ComplexNumber(realComponent: 1, imaginaryComponent: 0) - let minuend = ComplexNumber(realComponent: 2, imaginaryComponent: 0) - let expectedDifference = ComplexNumber(realComponent: -1, imaginaryComponent: 0) - let actualDifference = subtrahend.subtract(complexNumber: minuend) - - XCTAssertEqual([expectedDifference.realComponent, expectedDifference.imaginaryComponent], [actualDifference.realComponent, actualDifference.imaginaryComponent]) - } - - func testSubtractPurelyImaginaryNumbers() { - - let subtrahend = ComplexNumber(realComponent: 0, imaginaryComponent: 1) - let minuend = ComplexNumber(realComponent: 0, imaginaryComponent: 2) - let expectedDifference = ComplexNumber(realComponent: 0, imaginaryComponent: -1) - let actualDifference = subtrahend.subtract(complexNumber: minuend) - - XCTAssertEqual([expectedDifference.realComponent, expectedDifference.imaginaryComponent], [actualDifference.realComponent, actualDifference.imaginaryComponent]) - } - - func testSubtractNumbersWithRealAndImaginaryParts() { - - let subtrahend = ComplexNumber(realComponent: 1, imaginaryComponent: 2) - let minuend = ComplexNumber(realComponent: 3, imaginaryComponent: 4) - let expectedDifference = ComplexNumber(realComponent: -2, imaginaryComponent: -2) - let actualDifference = subtrahend.subtract(complexNumber: minuend) - - XCTAssertEqual([expectedDifference.realComponent, expectedDifference.imaginaryComponent], [actualDifference.realComponent, actualDifference.imaginaryComponent]) - - } - - func testMultiplicationOfPurelyRealNumbers() { - - let multiplicand = ComplexNumber(realComponent: 1, imaginaryComponent: 0) - let multiplier = ComplexNumber(realComponent: 2, imaginaryComponent: 0) - let expectedProduct = ComplexNumber(realComponent: 2, imaginaryComponent: 0) - let actualProduct = multiplicand.multiply(complexNumber: multiplier) - - XCTAssertEqual([expectedProduct.realComponent, expectedProduct.imaginaryComponent], [actualProduct.realComponent, actualProduct.imaginaryComponent]) - - } +import Foundation +import Testing - func testMultiplicationOfPurelyImaginaryNumbers() { - - let multiplicand = ComplexNumber(realComponent: 0, imaginaryComponent: 1) - let multiplier = ComplexNumber(realComponent: 0, imaginaryComponent: 2) - let expectedProduct = ComplexNumber(realComponent: -2, imaginaryComponent: 0) - let actualProduct = multiplicand.multiply(complexNumber: multiplier) - - XCTAssertEqual([expectedProduct.realComponent, expectedProduct.imaginaryComponent], [actualProduct.realComponent, actualProduct.imaginaryComponent]) - } - - func testMultiplyNumbersWithRealAndImaginaryParts() { - - let multiplicand = ComplexNumber(realComponent: 1, imaginaryComponent: 2) - let multiplier = ComplexNumber(realComponent: 3, imaginaryComponent: 4) - let expectedProduct = ComplexNumber(realComponent: -5, imaginaryComponent: 10) - let actualProduct = multiplicand.multiply(complexNumber: multiplier) - - XCTAssertEqual([expectedProduct.realComponent, expectedProduct.imaginaryComponent], [actualProduct.realComponent, actualProduct.imaginaryComponent]) - } - - func testDividePurelyRealNumbers() { - - let dividend = ComplexNumber(realComponent: 1, imaginaryComponent: 0) - let divisor = ComplexNumber(realComponent: 2, imaginaryComponent: 0) - let expectedQuotient = ComplexNumber(realComponent: 0.5, imaginaryComponent: 0) - let actualQuotient = dividend.divide(complexNumber: divisor) - - XCTAssertEqual([expectedQuotient.realComponent, expectedQuotient.imaginaryComponent], [actualQuotient.realComponent, actualQuotient.imaginaryComponent]) - } - - func testDividePurelyImaginaryNumbers() { - - let dividend = ComplexNumber(realComponent: 0, imaginaryComponent: 1) - let divisor = ComplexNumber(realComponent: 0, imaginaryComponent: 2) - let expectedQuotient = ComplexNumber(realComponent: 0.5, imaginaryComponent: 0) - let actualQuotient = dividend.divide(complexNumber: divisor) - - XCTAssertEqual([expectedQuotient.realComponent, expectedQuotient.imaginaryComponent], [actualQuotient.realComponent, actualQuotient.imaginaryComponent]) - } - - func testDividingNumbersWithRealAndImaginaryParts() { - - let dividend = ComplexNumber(realComponent: 1, imaginaryComponent: 2) - let divisor = ComplexNumber(realComponent: 3, imaginaryComponent: 4) - let expectedQuotient = ComplexNumber(realComponent: 0.44, imaginaryComponent: 0.08) - let actualQuotient = dividend.divide(complexNumber: divisor) - - XCTAssertEqual([expectedQuotient.realComponent, expectedQuotient.imaginaryComponent], [actualQuotient.realComponent, actualQuotient.imaginaryComponent]) - } - - func testAbsoluteValueOfPositivePurelyRealNumber() { - - let input = ComplexNumber(realComponent: 5, imaginaryComponent: 0) - let expectedResult = Double(5) - XCTAssertEqual(expectedResult, input.absolute()) - } - - func testAbsoluteValueOfNegativePurelyRealNumber() { - - let input = ComplexNumber(realComponent: -5, imaginaryComponent: 0) - let expectedResult = Double(5) - XCTAssertEqual(expectedResult, input.absolute()) - } - - func testAbsoluteValueOfPositivePurelyImaginaryNumber() { - - let input = ComplexNumber(realComponent: 0, imaginaryComponent: 5) - let expectedResult = Double(5) - XCTAssertEqual(expectedResult, input.absolute()) - } - - func testAbsoluteValueOfNegativePurelyImaginaryNumber() { - - let input = ComplexNumber(realComponent: 0, imaginaryComponent: -5) - let expectedResult = Double(5) - XCTAssertEqual(expectedResult, input.absolute()) - } - - func testAbsoluteValueOfNumberWithRealAndImaginaryParts() { - - let input = ComplexNumber(realComponent: 3, imaginaryComponent: 4) - let expectedResult = Double(5) - XCTAssertEqual(expectedResult, input.absolute()) - } - - func testConjugateOfAPurelyRealNumber() { - - let input = ComplexNumber(realComponent: 5, imaginaryComponent: 0) - let expectedResult = ComplexNumber(realComponent: 5, imaginaryComponent: 0) - let actualResult = input.conjugate() - XCTAssertEqual([expectedResult.realComponent, expectedResult.imaginaryComponent], [actualResult.realComponent, actualResult.imaginaryComponent]) - } - - func testConjugateOfAPurelyImaginaryNumber() { - - let input = ComplexNumber(realComponent: 0, imaginaryComponent: 5) - let expectedResult = ComplexNumber(realComponent: 0, imaginaryComponent: -5) - let actualResult = input.conjugate() - XCTAssertEqual([expectedResult.realComponent, expectedResult.imaginaryComponent], [actualResult.realComponent, actualResult.imaginaryComponent]) - } - - func testConjugateOfANumberWithRealAndImaginaryParts() { - - let input = ComplexNumber(realComponent: 1, imaginaryComponent: 1) - let expectedResult = ComplexNumber(realComponent: 1, imaginaryComponent: -1) - let actualResult = input.conjugate() - XCTAssertEqual([expectedResult.realComponent, expectedResult.imaginaryComponent], [actualResult.realComponent, actualResult.imaginaryComponent]) - } - - func testEulersIdentityForComplexNumbers() { - - let input = ComplexNumber(realComponent: 0, imaginaryComponent: Double(String(format: "%.3f", Double.pi))!) - let expectedResult = ComplexNumber(realComponent: -1, imaginaryComponent: 0) - let actualResult = input.exponent() - XCTAssertEqual([expectedResult.realComponent, expectedResult.imaginaryComponent], [Double(String(format: "%.3f", actualResult.realComponent))!, Double(String(format: "%.3f", actualResult.imaginaryComponent))!]) - - } - - func testExponentOfZero() { - - let input = ComplexNumber(realComponent: 0, imaginaryComponent: 0) - let expectedResult = ComplexNumber(realComponent: 1, imaginaryComponent: 0) - let actualResult = input.exponent() - XCTAssertEqual([expectedResult.realComponent, expectedResult.imaginaryComponent], [actualResult.realComponent, actualResult.imaginaryComponent]) - } - - func testExponentOfPurelyRealNumber() { - - let input = ComplexNumber(realComponent: 1, imaginaryComponent: 0) - let expectedResult = ComplexNumber(realComponent: exp(1), imaginaryComponent: 0) - let actualResult = input.exponent() - XCTAssertEqual([expectedResult.realComponent, expectedResult.imaginaryComponent], [actualResult.realComponent, actualResult.imaginaryComponent]) - } - - func testExponentOfNumberWithRealAndImaginaryPart() { +@testable import ComplexNumbers - let input = ComplexNumber(realComponent: log(2), imaginaryComponent: Double(String(format: "%.3f", Double.pi))!) - let expectedResult = ComplexNumber(realComponent: -2, imaginaryComponent: 0) - let actualResult = input.exponent() +let RUNALL = Bool(ProcessInfo.processInfo.environment["RUNALL", default: "true"]) ?? false + +@Suite struct ComplexNumbersTests { + + @Test("Real part of a purely real number") + func testRealPartOfAPurelyRealNumber() { + let complexNumber = ComplexNumbers(realComponent: 1, imaginaryComponent: 0) + #expect(complexNumber.real == 1) + } + + @Test("Real part of a purely imaginary number", .enabled(if: RUNALL)) + func testRealPartOfAPurelyImaginaryNumber() { + let complexNumber = ComplexNumbers(realComponent: 0, imaginaryComponent: 1) + #expect(complexNumber.real == 0) + } + + @Test("Real part of a number with real and imaginary part", .enabled(if: RUNALL)) + func testRealPartOfANumberWithRealAndImaginaryPart() { + let complexNumber = ComplexNumbers(realComponent: 1, imaginaryComponent: 2) + #expect(complexNumber.real == 1) + } + + @Test("Imaginary part of a purely real number", .enabled(if: RUNALL)) + func testImaginaryPartOfAPurelyRealNumber() { + let complexNumber = ComplexNumbers(realComponent: 1, imaginaryComponent: 0) + #expect(complexNumber.imaginary == 0) + } + + @Test("Imaginary part of a purely imaginary number", .enabled(if: RUNALL)) + func testImaginaryPartOfAPurelyImaginaryNumber() { + let complexNumber = ComplexNumbers(realComponent: 0, imaginaryComponent: 1) + #expect(complexNumber.imaginary == 1) + } + + @Test("Imaginary part of a number with real and imaginary part", .enabled(if: RUNALL)) + func testImaginaryPartOfANumberWithRealAndImaginaryPart() { + let complexNumber = ComplexNumbers(realComponent: 1, imaginaryComponent: 2) + #expect(complexNumber.imaginary == 2) + } + + @Test("Imaginary unit", .enabled(if: RUNALL)) + func testImaginaryUnit() { + let complexNumberOne = ComplexNumbers(realComponent: 0, imaginaryComponent: 1) + let complexNumberTwo = ComplexNumbers(realComponent: 0, imaginaryComponent: 1) + let result = complexNumberOne.mul(complexNumber: complexNumberTwo) + let expected = ComplexNumbers(realComponent: -1, imaginaryComponent: 0) + #expect(expected == result) + } + + @Test("Add purely real numbers", .enabled(if: RUNALL)) + func testAddPurelyRealNumbers() { + let complexNumberOne = ComplexNumbers(realComponent: 1, imaginaryComponent: 0) + let complexNumberTwo = ComplexNumbers(realComponent: 2, imaginaryComponent: 0) + let result = complexNumberOne.add(complexNumber: complexNumberTwo) + let expected = ComplexNumbers(realComponent: 3, imaginaryComponent: 0) + #expect(expected == result) + } + @Test("Add purely imaginary numbers", .enabled(if: RUNALL)) + func testAddPurelyImaginaryNumbers() { + let complexNumberOne = ComplexNumbers(realComponent: 0, imaginaryComponent: 1) + let complexNumberTwo = ComplexNumbers(realComponent: 0, imaginaryComponent: 2) + let result = complexNumberOne.add(complexNumber: complexNumberTwo) + let expected = ComplexNumbers(realComponent: 0, imaginaryComponent: 3) + #expect(expected == result) + } + @Test("Add numbers with real and imaginary part", .enabled(if: RUNALL)) + func testAddNumbersWithRealAndImaginaryPart() { + let complexNumberOne = ComplexNumbers(realComponent: 1, imaginaryComponent: 2) + let complexNumberTwo = ComplexNumbers(realComponent: 3, imaginaryComponent: 4) + let result = complexNumberOne.add(complexNumber: complexNumberTwo) + let expected = ComplexNumbers(realComponent: 4, imaginaryComponent: 6) + #expect(expected == result) + } + + @Test("Subtract purely real numbers", .enabled(if: RUNALL)) + func testSubtractPurelyRealNumbers() { + let complexNumberOne = ComplexNumbers(realComponent: 1, imaginaryComponent: 0) + let complexNumberTwo = ComplexNumbers(realComponent: 2, imaginaryComponent: 0) + let result = complexNumberOne.sub(complexNumber: complexNumberTwo) + let expected = ComplexNumbers(realComponent: -1, imaginaryComponent: 0) + #expect(expected == result) + } + @Test("Subtract purely imaginary numbers", .enabled(if: RUNALL)) + func testSubtractPurelyImaginaryNumbers() { + let complexNumberOne = ComplexNumbers(realComponent: 0, imaginaryComponent: 1) + let complexNumberTwo = ComplexNumbers(realComponent: 0, imaginaryComponent: 2) + let result = complexNumberOne.sub(complexNumber: complexNumberTwo) + let expected = ComplexNumbers(realComponent: 0, imaginaryComponent: -1) + #expect(expected == result) + } + @Test("Subtract numbers with real and imaginary part", .enabled(if: RUNALL)) + func testSubtractNumbersWithRealAndImaginaryPart() { + let complexNumberOne = ComplexNumbers(realComponent: 1, imaginaryComponent: 2) + let complexNumberTwo = ComplexNumbers(realComponent: 3, imaginaryComponent: 4) + let result = complexNumberOne.sub(complexNumber: complexNumberTwo) + let expected = ComplexNumbers(realComponent: -2, imaginaryComponent: -2) + #expect(expected == result) + } + + @Test("Multiply purely real numbers", .enabled(if: RUNALL)) + func testMultiplyPurelyRealNumbers() { + let complexNumberOne = ComplexNumbers(realComponent: 1, imaginaryComponent: 0) + let complexNumberTwo = ComplexNumbers(realComponent: 2, imaginaryComponent: 0) + let result = complexNumberOne.mul(complexNumber: complexNumberTwo) + let expected = ComplexNumbers(realComponent: 2, imaginaryComponent: 0) + #expect(expected == result) + } + @Test("Multiply purely imaginary numbers", .enabled(if: RUNALL)) + func testMultiplyPurelyImaginaryNumbers() { + let complexNumberOne = ComplexNumbers(realComponent: 0, imaginaryComponent: 1) + let complexNumberTwo = ComplexNumbers(realComponent: 0, imaginaryComponent: 2) + let result = complexNumberOne.mul(complexNumber: complexNumberTwo) + let expected = ComplexNumbers(realComponent: -2, imaginaryComponent: 0) + #expect(expected == result) + } + @Test("Multiply numbers with real and imaginary part", .enabled(if: RUNALL)) + func testMultiplyNumbersWithRealAndImaginaryPart() { + let complexNumberOne = ComplexNumbers(realComponent: 1, imaginaryComponent: 2) + let complexNumberTwo = ComplexNumbers(realComponent: 3, imaginaryComponent: 4) + let result = complexNumberOne.mul(complexNumber: complexNumberTwo) + let expected = ComplexNumbers(realComponent: -5, imaginaryComponent: 10) + #expect(expected == result) + } + + @Test("Divide purely real numbers", .enabled(if: RUNALL)) + func testDividePurelyRealNumbers() { + let complexNumberOne = ComplexNumbers(realComponent: 1, imaginaryComponent: 0) + let complexNumberTwo = ComplexNumbers(realComponent: 2, imaginaryComponent: 0) + let result = complexNumberOne.div(complexNumber: complexNumberTwo) + let expected = ComplexNumbers(realComponent: 0.5, imaginaryComponent: 0) + #expect(expected == result) + } + @Test("Divide purely imaginary numbers", .enabled(if: RUNALL)) + func testDividePurelyImaginaryNumbers() { + let complexNumberOne = ComplexNumbers(realComponent: 0, imaginaryComponent: 1) + let complexNumberTwo = ComplexNumbers(realComponent: 0, imaginaryComponent: 2) + let result = complexNumberOne.div(complexNumber: complexNumberTwo) + let expected = ComplexNumbers(realComponent: 0.5, imaginaryComponent: 0) + #expect(expected == result) + } + @Test("Divide numbers with real and imaginary part", .enabled(if: RUNALL)) + func testDivideNumbersWithRealAndImaginaryPart() { + let complexNumberOne = ComplexNumbers(realComponent: 1, imaginaryComponent: 2) + let complexNumberTwo = ComplexNumbers(realComponent: 3, imaginaryComponent: 4) + let result = complexNumberOne.div(complexNumber: complexNumberTwo) + let expected = ComplexNumbers(realComponent: 0.44, imaginaryComponent: 0.08) + #expect(expected == result) + } + + @Test("Absolute value of a positive purely real number", .enabled(if: RUNALL)) + func testAbsoluteValueOfAPositivePurelyRealNumber() { + let complexNumber = ComplexNumbers(realComponent: 5, imaginaryComponent: 0) + #expect(complexNumber.absolute() == 5) + } + + @Test("Absolute value of a negative purely real number", .enabled(if: RUNALL)) + func testAbsoluteValueOfANegativePurelyRealNumber() { + let complexNumber = ComplexNumbers(realComponent: -5, imaginaryComponent: 0) + #expect(complexNumber.absolute() == 5) + } + + @Test( + "Absolute value of a purely imaginary number with positive imaginary part", .enabled(if: RUNALL) + ) + func testAbsoluteValueOfAPurelyImaginaryNumberWithPositiveImaginaryPart() { + let complexNumber = ComplexNumbers(realComponent: 0, imaginaryComponent: 5) + #expect(complexNumber.absolute() == 5) + } + + @Test( + "Absolute value of a purely imaginary number with negative imaginary part", .enabled(if: RUNALL) + ) + func testAbsoluteValueOfAPurelyImaginaryNumberWithNegativeImaginaryPart() { + let complexNumber = ComplexNumbers(realComponent: 0, imaginaryComponent: -5) + #expect(complexNumber.absolute() == 5) + } + + @Test("Absolute value of a number with real and imaginary part", .enabled(if: RUNALL)) + func testAbsoluteValueOfANumberWithRealAndImaginaryPart() { + let complexNumber = ComplexNumbers(realComponent: 3, imaginaryComponent: 4) + #expect(complexNumber.absolute() == 5) + } + + @Test("Conjugate a purely real number", .enabled(if: RUNALL)) + func testConjugateAPurelyRealNumber() { + let complexNumber = ComplexNumbers(realComponent: 5, imaginaryComponent: 0) + let expected = ComplexNumbers(realComponent: 5, imaginaryComponent: 0) + #expect(complexNumber.conjugate() == expected) + } + + @Test("Conjugate a purely imaginary number", .enabled(if: RUNALL)) + func testConjugateAPurelyImaginaryNumber() { + let complexNumber = ComplexNumbers(realComponent: 0, imaginaryComponent: 5) + let expected = ComplexNumbers(realComponent: 0, imaginaryComponent: -5) + #expect(complexNumber.conjugate() == expected) + } + + @Test("Conjugate a number with real and imaginary part", .enabled(if: RUNALL)) + func testConjugateANumberWithRealAndImaginaryPart() { + let complexNumber = ComplexNumbers(realComponent: 1, imaginaryComponent: 1) + let expected = ComplexNumbers(realComponent: 1, imaginaryComponent: -1) + #expect(complexNumber.conjugate() == expected) + } + + @Test("Euler's identity/formula", .enabled(if: RUNALL)) + func testEulersIdentityformula() { + let complexNumber = ComplexNumbers(realComponent: 0, imaginaryComponent: Double.pi) + let expected = ComplexNumbers(realComponent: -1, imaginaryComponent: 0) + #expect(complexNumber.exponent() == expected) + } + + @Test("Exponential of 0", .enabled(if: RUNALL)) + func testExponentialOf0() { + let complexNumber = ComplexNumbers(realComponent: 0, imaginaryComponent: 0) + let expected = ComplexNumbers(realComponent: 1, imaginaryComponent: 0) + #expect(complexNumber.exponent() == expected) + } + + @Test("Exponential of a purely real number", .enabled(if: RUNALL)) + func testExponentialOfAPurelyRealNumber() { + let complexNumber = ComplexNumbers(realComponent: 1, imaginaryComponent: 0) + let expected = ComplexNumbers(realComponent: exp(1), imaginaryComponent: 0) + #expect(complexNumber.exponent() == expected) + } + + @Test("Exponential of a number with real and imaginary part", .enabled(if: RUNALL)) + func testExponentialOfANumberWithRealAndImaginaryPart() { + let complexNumber = ComplexNumbers(realComponent: log(2), imaginaryComponent: Double.pi) + let expected = ComplexNumbers(realComponent: -2, imaginaryComponent: 0) + #expect(complexNumber.exponent() == expected) + } + + @Test("Exponential resulting in a number with real and imaginary part", .enabled(if: RUNALL)) + func testExponentialResultingInANumberWithRealAndImaginaryPart() { + let complexNumber = ComplexNumbers(realComponent: log(2) / 2, imaginaryComponent: Double.pi / 4) + let expected = ComplexNumbers(realComponent: 1, imaginaryComponent: 1) + #expect(complexNumber.exponent() == expected) + } + + @Test("Add real number to complex number", .enabled(if: RUNALL)) + func testAddRealNumberToComplexNumber() { + let complexNumberOne = ComplexNumbers(realComponent: 1, imaginaryComponent: 2) + let complexNumberTwo = ComplexNumbers(realComponent: 5, imaginaryComponent: nil) + let result = complexNumberOne.add(complexNumber: complexNumberTwo) + let expected = ComplexNumbers(realComponent: 6, imaginaryComponent: 2) + #expect(expected == result) + } + + @Test("Add complex number to real number", .enabled(if: RUNALL)) + func testAddComplexNumberToRealNumber() { + let complexNumberOne = ComplexNumbers(realComponent: 5, imaginaryComponent: nil) + let complexNumberTwo = ComplexNumbers(realComponent: 1, imaginaryComponent: 2) + let result = complexNumberOne.add(complexNumber: complexNumberTwo) + let expected = ComplexNumbers(realComponent: 6, imaginaryComponent: 2) + #expect(expected == result) + } + + @Test("Subtract real number from complex number", .enabled(if: RUNALL)) + func testSubtractRealNumberFromComplexNumber() { + let complexNumberOne = ComplexNumbers(realComponent: 5, imaginaryComponent: 7) + let complexNumberTwo = ComplexNumbers(realComponent: 4, imaginaryComponent: nil) + let result = complexNumberOne.sub(complexNumber: complexNumberTwo) + let expected = ComplexNumbers(realComponent: 1, imaginaryComponent: 7) + #expect(expected == result) + } + + @Test("Subtract complex number from real number", .enabled(if: RUNALL)) + func testSubtractComplexNumberFromRealNumber() { + let complexNumberOne = ComplexNumbers(realComponent: 4, imaginaryComponent: nil) + let complexNumberTwo = ComplexNumbers(realComponent: 5, imaginaryComponent: 7) + let result = complexNumberOne.sub(complexNumber: complexNumberTwo) + let expected = ComplexNumbers(realComponent: -1, imaginaryComponent: -7) + #expect(expected == result) + } + + @Test("Multiply complex number by real number", .enabled(if: RUNALL)) + func testMultiplyComplexNumberByRealNumber() { + let complexNumberOne = ComplexNumbers(realComponent: 2, imaginaryComponent: 5) + let complexNumberTwo = ComplexNumbers(realComponent: 5, imaginaryComponent: nil) + let result = complexNumberOne.mul(complexNumber: complexNumberTwo) + let expected = ComplexNumbers(realComponent: 10, imaginaryComponent: 25) + #expect(expected == result) + } + + @Test("Multiply real number by complex number", .enabled(if: RUNALL)) + func testMultiplyRealNumberByComplexNumber() { + let complexNumberOne = ComplexNumbers(realComponent: 5, imaginaryComponent: nil) + let complexNumberTwo = ComplexNumbers(realComponent: 2, imaginaryComponent: 5) + let result = complexNumberOne.mul(complexNumber: complexNumberTwo) + let expected = ComplexNumbers(realComponent: 10, imaginaryComponent: 25) + #expect(expected == result) + } + + @Test("Divide complex number by real number", .enabled(if: RUNALL)) + func testDivideComplexNumberByRealNumber() { + let complexNumberOne = ComplexNumbers(realComponent: 10, imaginaryComponent: 100) + let complexNumberTwo = ComplexNumbers(realComponent: 10, imaginaryComponent: nil) + let result = complexNumberOne.div(complexNumber: complexNumberTwo) + let expected = ComplexNumbers(realComponent: 1, imaginaryComponent: 10) + #expect(expected == result) + } + + @Test("Divide real number by complex number", .enabled(if: RUNALL)) + func testDivideRealNumberByComplexNumber() { + let complexNumberOne = ComplexNumbers(realComponent: 5, imaginaryComponent: nil) + let complexNumberTwo = ComplexNumbers(realComponent: 1, imaginaryComponent: 1) + let result = complexNumberOne.div(complexNumber: complexNumberTwo) + let expected = ComplexNumbers(realComponent: 2.5, imaginaryComponent: -2.5) + #expect(expected == result) + } - XCTAssertEqual([expectedResult.realComponent, expectedResult.imaginaryComponent], [round(actualResult.realComponent), Double(String(format: "%.1f", actualResult.imaginaryComponent))!]) - } } diff --git a/exercises/practice/poker/.meta/Sources/Poker/PokerExample.swift b/exercises/practice/poker/.meta/Sources/Poker/PokerExample.swift index f1698d45a..1708bcd6e 100644 --- a/exercises/practice/poker/.meta/Sources/Poker/PokerExample.swift +++ b/exercises/practice/poker/.meta/Sources/Poker/PokerExample.swift @@ -1,367 +1,236 @@ import Foundation -private extension String { +enum HandRank: Int, Comparable { + case highCard, onePair, twoPair, threeOfAKind, straight, flush, fullHouse, fourOfAKind, + straightFlush - func split(_ input: String) -> [String] { - return self.components(separatedBy: input) - } - // Returns the Rank part of the card - func head() -> String { - return String(self[.. String { - return String(self[index(before: endIndex).. Bool { + return lhs.rawValue < rhs.rawValue + } } -struct Poker { - - static func bestHand(_ hands: [String]) -> String? { - - var pokerHandsParsed: [PokerHand] = [] - - for each in hands { - guard let pokerHand = PokerHand(each) else { return nil } - pokerHandsParsed.append(pokerHand) +class Poker { + var hands: [[String]] + + init(_ hands: [String]) { + self.hands = hands.map { $0.components(separatedBy: " ") } + } + + func bestHands() -> String { + var bestRank: HandRank = .highCard + var bestRankedHands: [[String]] = [] + + for hand in hands { + let rank = evaluateHand(hand) + if rank > bestRank { + bestRank = rank + bestRankedHands = [hand] + } else if rank == bestRank { + bestRankedHands.append(hand) + } + } + let bestHand = breakTies(between: bestRankedHands, for: bestRank) + return bestHand.joined(separator: " ") + } + + private func convertValue(_ value: String, _ flush: Bool = false) -> Int { + let value = String(value.prefix(value.count - 1)) + + if flush == true && value == "A" { + return 1 + } + + switch value { + case "J": return 11 + case "Q": return 12 + case "K": return 13 + case "A": return 14 + default: return Int(value)! + } + } + + private func evaluateHand(_ hand: [String]) -> HandRank { + + // This method evaluates the rank of the hand + // For simplicity, this example returns a high card rank. + // You need to implement full hand ranking logic here. + + let sortedHand = hand.sorted { card1, card2 in + let value1 = convertValue(card1) + let value2 = convertValue(card2) + return value1 < value2 + } + + // Check for flush + let flush = sortedHand.allSatisfy { $0.last == sortedHand[0].last } + + var sortedHandFlush = sortedHand + + if sortedHand.last?.prefix(1) == "A" && sortedHand.first?.prefix(1) == "2" { + sortedHandFlush.removeLast() + } + + let straight = sortedHandFlush.enumerated().allSatisfy { index, card in + if index == 0 { + return true + } + + let value1 = convertValue(sortedHandFlush[index - 1]) + let value2 = convertValue(card) + return value2 - value1 == 1 + } + + let fullHouse = sortedHand.enumerated().contains { index, card in + if index + 4 < sortedHand.count { + return sortedHand[index].prefix(sortedHand[index].count - 1) + == sortedHand[index + 1].prefix(sortedHand[index + 1].count - 1) + && sortedHand[index].prefix(sortedHand[index].count - 1) + == sortedHand[index + 2].prefix(sortedHand[index + 2].count - 1) + && sortedHand[index + 3].prefix(sortedHand[index + 3].count - 1) + == sortedHand[index + 4].prefix(sortedHand[index + 4].count - 1) + } + return false + } + + let cardCounts = Dictionary(grouping: hand, by: { convertValue($0) }) + let twoPair = cardCounts.values.filter { $0.count == 2 }.count == 2 + let onePair = cardCounts.values.contains { $0.count == 2 } + let threeOfAKind = cardCounts.values.contains { $0.count == 3 } + let fourOfAKind = cardCounts.values.contains { $0.count == 4 } + + if flush && straight { + return .straightFlush + } else if fourOfAKind { + return .fourOfAKind + } else if fullHouse { + return .fullHouse + } else if flush { + return .flush + } else if straight { + return .straight + } else if threeOfAKind { + return .threeOfAKind + } else if twoPair { + return .twoPair + } else if onePair { + return .onePair + } + return .highCard + } + + private func breakTies(between hands: [[String]], for rank: HandRank) -> [String] { + // This method resolves ties between hands of the same rank + // For simplicity, this example returns the hands as-is. + // You need to implement tie-breaking logic here. + + if rank == .highCard || rank == .straightFlush || rank == .straight || rank == .flush { + return hands.max { hand1, hand2 in + let isFlush = rank == .straight || rank == .straightFlush + + func highestCard(_ hand: [String]) -> String { + return hand.max { card1, card2 in + convertValue(card1, isFlush) < convertValue(card2, isFlush) + }! } - guard let topHand = (pokerHandsParsed.sorted(by: >)).first, - let indexTop = pokerHandsParsed.index(of: topHand) else { return nil } - - return hands[indexTop] - - } -} - -enum HandRank { - case highCard(PlayingCard) - case onePair(Rank, card1:Rank, card2:Rank, card3:Rank ) - case twoPair(high:Rank, low:Rank, highCard:PlayingCard) - case threeOfAKind(three:Rank) - case straight(high:Rank) - case flush(Rank, Suit) - case fullHouse(three:Rank) - case fourOfAKind(four:Rank) - case straightFlush(Rank, Suit) + var hand1High = highestCard(hand1) + var hand2High = highestCard(hand2) - func order() -> Int { - switch self { - case .highCard: return 1 - case .onePair: return 2 - case .twoPair: return 3 - case .threeOfAKind: return 4 - case .straight: return 5 - case .flush: return 6 - case .fullHouse: return 7 - case .fourOfAKind: return 8 - case .straightFlush: return 9 - } - } - - static func parsePairs(_ inputHand: PokerHand) -> [(rank: Rank, count: Int)] { - let ranks = inputHand.hand.map({ $0.rank }) - let rankSet = Set(ranks) - var toReturn = [Rank: Int]() - for each in ranks { - if rankSet.contains(each) { - toReturn[each] = (toReturn[each] ?? 0) + 1 - } - } - let preresult = toReturn.map({ key, value in return (rank:key, count:value) }) - return preresult.sorted(by: { (one, two) in - return one.count == two.count ? one.rank > two.rank : one.count > two.count - }) - } + var hand1 = hand1 + var hand2 = hand2 - static func isFlush(_ inputHand: PokerHand) -> (bool: Bool, suit: Suit) { - let suits = inputHand.hand.map({ $0.suit }) - let first = suits[0] - for each in suits { - guard first == each else { return (false, .none) } + while convertValue(hand1High) == convertValue(hand2High) { + hand1 = hand1.filter { $0 != hand1High } + hand2 = hand2.filter { $0 != hand2High } + if hand1.isEmpty { + return false + } + hand1High = highestCard(hand1) + hand2High = highestCard(hand2) } - return (true, first) - } - static func isStraight(_ inputHand: PokerHand) -> (bool: Bool, highest: Rank) { - let sorted = inputHand.hand.sorted(by: { $0.rank < $1.rank }) - let first = sorted[0].rank.rawValue - for (index, each) in sorted.enumerated() { - guard each.rank.rawValue != index + first else { continue } - // checks for Ace as the lowest card - guard let aceIndex = inputHand.hand.index(where: { $0.rank.rawValue == 14 })else { return (false, .ace) } - var replacedAced = inputHand.hand.map({ $0.rank.rawValue }) - replacedAced[aceIndex] = 1 // swaps ace value to lowest - replacedAced.sort() - let firstVal = replacedAced[0] - for (idx, eachVal) in replacedAced.enumerated() { - guard eachVal == firstVal + idx else { return (false, .ace) } + return convertValue(hand1High) < convertValue(hand2High) + }! + } else if rank == .onePair { + + let bestHand = hands.max { left, right in + func pairValue(_ hand: [String]) -> Int { + for i in 0.. Bool { - switch (lhs, rhs) { - //straightFlush(Rank,Suit) - case (HandRank.straightFlush(let lRank, let lSuit), HandRank.straightFlush(let rRank, let rSuit)): - return lRank == rRank && lSuit == rSuit - //fourOfAKind(four:Rank) - case (HandRank.fourOfAKind(four: let lFour), - HandRank.fourOfAKind(four: let rFour)): - return lFour == rFour - //fullHouse(three:Rank) - case (HandRank.fullHouse(three: let lThree), - HandRank.fullHouse(three: let rThree)): - return lThree == rThree - //flush(Suit) - case (HandRank.flush(let lRank, let lSuit), HandRank.flush(let rRank, let rSuit)): - return lSuit == rSuit && lRank == rRank - //straight(high:Rank) - case (HandRank.straight(high: let lRank), - HandRank.straight(high: let rRank)): - return lRank == rRank - //threeOfAKind(three:Rank) - case (HandRank.threeOfAKind(three: let lRank), - HandRank.threeOfAKind(three: let rRank)): - return lRank == rRank - //twoPair(high:Rank,low:Rank, highCard:PlayingCard) - case (HandRank.twoPair(high: let lHigh, low: let lLow, highCard: let lCard), HandRank.twoPair(high: let rHigh, low: let rLow, highCard: let rCard)): - return lHigh == rHigh && lLow == rLow && lCard == rCard - //onePair(Rank) - case (HandRank.onePair(let lPairRank, card1: let lCard1, card2: let lCard2, card3: let lCard3), - HandRank.onePair(let rPairRank, card1: let rCard1, card2: let rCard2, card3: let rCard3)): - return lPairRank == rPairRank && lCard1 == rCard1 && lCard2 == rCard2 && lCard3 == rCard3 - //highCard(PlayingCard) - case (HandRank.highCard(let lCard), HandRank.highCard(let rCard)): - return lCard == rCard - default: - return false + return pairValue(left) < pairValue(right) + }! + return bestHand + + } else if rank == .twoPair { + let bestHand = hands.max { left, right in + func pairValue(_ hand: [String]) -> Int { + var counts = [Int: Int]() + for card in hand { + let value = convertValue(card) + counts[value, default: 0] += 1 + } + return counts.filter { $0.value == 2 }.max(by: { $0.key < $1.key })!.key } - } -} - -extension HandRank: Comparable { - // swiftlint:disable cyclomatic_complexity - static func < (lhs: HandRank, rhs: HandRank) -> Bool { - switch (lhs, rhs) { - case (_, _) where lhs == rhs: - return false - - //straightFlush(Rank,Suit) - case (HandRank.straightFlush(let lRank, let lSuit), HandRank.straightFlush(let rRank, let rSuit)): - return lRank == rRank ? lSuit < rSuit : lRank < rRank - - //fourOfAKind(four:Rank) - case (HandRank.fourOfAKind(four: let lFour), - HandRank.fourOfAKind(four: let rFour)): - return lFour < rFour - - //fullHouse(three:Rank) - case (HandRank.fullHouse(three: let lRank), - HandRank.fullHouse(three: let rRank)): - return lRank < rRank - - //flush(Suit) - case (HandRank.flush(let lRank, let lSuit), HandRank.flush(let rRank, let rSuit)): - return lRank == rRank ? lSuit < rSuit : lRank < rRank - - //straight(high:Rank) - case (HandRank.straight(high: let lRank), - HandRank.straight(high: let rRank)): - return lRank < rRank - - //threeOfAKind(three:Rank) - case (HandRank.threeOfAKind(three: let lRank), - HandRank.threeOfAKind(three: let rRank)): - return lRank < rRank - - //twoPair(high:Rank,low:Rank, highCard:PlayingCard) - case (HandRank.twoPair(high: let lHigh, low: let lLow, highCard: let lCard), HandRank.twoPair(high: let rHigh, low: let rLow, highCard: let rCard)): - if lHigh == rHigh && lLow == rLow { - return lCard < rCard - } else { - return lHigh < rHigh - } - - //onePair(Rank) - case (HandRank.onePair(let lPairRank, card1: let lCard1, card2: let lCard2, card3: let lCard3), - HandRank.onePair(let rPairRank, card1: let rCard1, card2: let rCard2, card3: let rCard3)): - return lPairRank == rPairRank ? (lCard1 == rCard1 ? (lCard2 == rCard2 ? lCard3 < rCard3 :lCard2 < rCard2):lCard1 < rCard1):lPairRank < rPairRank - - //highCard(PlayingCard) - case (HandRank.highCard(let lCard), HandRank.highCard(let rCard)): - return lCard < rCard - - default: - return lhs.order() < rhs.order() + if pairValue(left) == pairValue(right) { + let leftHighest = pairValue(left.filter { convertValue($0) != pairValue(left) }) + let rightHighest = pairValue( + right.filter { convertValue($0) != pairValue(right) }) + return leftHighest < rightHighest } - } -} - -struct PokerHand { - let hand: [PlayingCard] - - func handRank() -> HandRank { - return HandRank(self) - } - - init?(_ stringHand: String) { - - var handParsed: [PlayingCard] = [] - - for each in stringHand.split(" ") { - guard let card = PlayingCard(each) else { return nil } - handParsed.append(card) + return pairValue(left) < pairValue(right) + }! + return bestHand + + } else if rank == .threeOfAKind || rank == .fullHouse { + let bestHand = hands.max { left, right in + func tripValue(_ hand: [String]) -> Int { + var counts = [Int: Int]() + for card in hand { + let value = convertValue(card) + counts[value, default: 0] += 1 + } + return counts.first(where: { $0.value == 3 })?.key ?? 0 } - - if handParsed.count == 5 { self.hand = handParsed } else { return nil } - } -} - -extension PokerHand: Equatable { - static func == (lhs: PokerHand, rhs: PokerHand) -> Bool { - return lhs.hand == rhs.hand - } -} - -extension PokerHand: Comparable { - static func < (lhs: PokerHand, rhs: PokerHand) -> Bool { - return lhs.handRank() < rhs.handRank() - } -} - -struct PlayingCard { - let rank: Rank - let suit: Suit - - init(rank: Rank, suit: Suit) { - self.rank = rank - self.suit = suit - } - - init?(_ stringInput: String) { - - guard let rank = Rank(stringInput.head()), - let suit = Suit(stringInput.tail()) else { return nil } - - self.rank = rank - self.suit = suit - } -} - -extension PlayingCard: Equatable { - static func == (lhs: PlayingCard, rhs: PlayingCard) -> Bool { - return lhs.rank == rhs.rank && lhs.suit == rhs.suit - } -} - -extension PlayingCard: Comparable { - static func < (lhs: PlayingCard, rhs: PlayingCard) -> Bool { - return lhs.rank == rhs.rank ? lhs.suit < rhs.suit : lhs.rank < rhs.rank - } -} - -enum Rank: Int { - case two = 2 - case three, four, five, six, seven, eight, nine, ten - case jack, queen, king, ace - - init?(_ rank: String) { - var rankInt = 0 - switch rank { - case "A": rankInt = 14 - case "J": rankInt = 11 - case "Q": rankInt = 12 - case "K": rankInt = 13 - default : rankInt = Int(rank) ?? 0 + if tripValue(left) == tripValue(right) { + let rightHighest = right.filter { convertValue($0) != tripValue(right) }.max( + by: { convertValue($0) < convertValue($1) })! + let leftHighest = left.filter { convertValue($0) != tripValue(left) }.max(by: { + convertValue($0) < convertValue($1) + })! + return convertValue(leftHighest) < convertValue(rightHighest) } - self.init(rawValue: rankInt) - } -} -enum Suit: String { - case spades, hearts, diamonds, clubs - case none - - init?(_ suit: String) { - - switch suit { - case "♡": self = .hearts - case "♢": self = .diamonds - case "♧": self = .clubs - case "♤": self = .spades - case _ : return nil + return tripValue(left) < tripValue(right) + }! + return bestHand + } else if rank == .fourOfAKind { + let bestHand = hands.max { left, right in + func quadValue(_ hand: [String]) -> Int { + var counts = [Int: Int]() + for card in hand { + let value = convertValue(card) + counts[value, default: 0] += 1 + } + return counts.first(where: { $0.value == 4 })?.key ?? 0 } - } -} - -extension Rank: Comparable { - static func < (lhs: Rank, rhs: Rank) -> Bool { - switch (lhs, rhs) { - case (_, _) where lhs == rhs: - return false - default: - return lhs.rawValue < rhs.rawValue + if quadValue(left) == quadValue(right) { + let rightHighest = right.filter { convertValue($0) != quadValue(right) } + let leftHighest = left.filter { convertValue($0) != quadValue(left) } + return convertValue(leftHighest[0]) < convertValue(rightHighest[0]) } - } -} + return quadValue(left) < quadValue(right) + }! + return bestHand -extension Suit: Comparable { - static func < (lhs: Suit, rhs: Suit) -> Bool { - switch (lhs, rhs) { - case (_, _) where lhs == rhs: - return false - case (.spades, _), - (.hearts, .diamonds), (.hearts, .clubs), - (.diamonds, .clubs): - return false - default: - return true - } + } else { + return hands[0] } + } } diff --git a/exercises/practice/poker/.meta/template.swift b/exercises/practice/poker/.meta/template.swift new file mode 100644 index 000000000..1fb437436 --- /dev/null +++ b/exercises/practice/poker/.meta/template.swift @@ -0,0 +1,21 @@ +import Testing +import Foundation +@testable import {{exercise|camelCase}} + +let RUNALL = Bool(ProcessInfo.processInfo.environment["RUNALL", default: "false"]) ?? false + +@Suite struct {{exercise|camelCase}}Tests { + {% for case in cases %} + {% if forloop.first -%} + @Test("{{case.description}}") + {% else -%} + @Test("{{case.description}}", .enabled(if: RUNALL)) + {% endif -%} + func test{{case.description |camelCase }}() { + let poker = {{exercise|camelCase}}({{case.input.hands}}) + let bestHand = poker.{{case.property}}() + let expected = "{{case.expected[0]}}" + #expect(bestHand == expected) + } +{% endfor -%} +} \ No newline at end of file diff --git a/exercises/practice/poker/.meta/tests.toml b/exercises/practice/poker/.meta/tests.toml index 35baf626a..2e654ef63 100644 --- a/exercises/practice/poker/.meta/tests.toml +++ b/exercises/practice/poker/.meta/tests.toml @@ -21,12 +21,18 @@ description = "a tie has multiple winners" [61ed83a9-cfaa-40a5-942a-51f52f0a8725] description = "multiple hands with the same high cards, tie compares next highest ranked, down to last card" +[da01becd-f5b0-4342-b7f3-1318191d0580] +description = "winning high card hand also has the lowest card" + [f7175a89-34ff-44de-b3d7-f6fd97d1fca4] description = "one pair beats high card" [e114fd41-a301-4111-a9e7-5a7f72a76561] description = "highest pair wins" +[b3acd3a7-f9fa-4647-85ab-e0a9e07d1365] +description = "both hands have the same pair, high card wins" + [935bb4dc-a622-4400-97fa-86e7d06b1f76] description = "two pairs beats one pair" @@ -39,6 +45,12 @@ description = "both hands have two pairs, with the same highest ranked pair, tie [15a7a315-0577-47a3-9981-d6cf8e6f387b] description = "both hands have two identically ranked pairs, tie goes to remaining card (kicker)" +[f761e21b-2560-4774-a02a-b3e9366a51ce] +description = "both hands have two pairs that add to the same value, win goes to highest pair" + +[fc6277ac-94ac-4078-8d39-9d441bc7a79e] +description = "two pairs first ranked by largest pair" + [21e9f1e6-2d72-49a1-a930-228e5e0195dc] description = "three of a kind beats two pair" @@ -47,6 +59,11 @@ description = "both hands have three of a kind, tie goes to highest ranked tripl [eb856cc2-481c-4b0d-9835-4d75d07a5d9d] description = "with multiple decks, two players can have same three of a kind, ties go to highest remaining cards" +include = false + +[26a4a7d4-34a2-4f18-90b4-4a8dd35d2bb1] +description = "with multiple decks, two players can have same three of a kind, ties go to highest remaining cards" +reimplements = "eb856cc2-481c-4b0d-9835-4d75d07a5d9d" [a858c5d9-2f28-48e7-9980-b7fa04060a60] description = "a straight beats three of a kind" @@ -57,6 +74,9 @@ description = "aces can end a straight (10 J Q K A)" [76856b0d-35cd-49ce-a492-fe5db53abc02] description = "aces can start a straight (A 2 3 4 5)" +[e214b7df-dcba-45d3-a2e5-342d8c46c286] +description = "aces cannot be in the middle of a straight (Q K A 2 3)" + [6980c612-bbff-4914-b17a-b044e4e69ea1] description = "both hands with a straight, tie goes to highest ranked card" @@ -68,6 +88,11 @@ description = "flush beats a straight" [4d90261d-251c-49bd-a468-896bf10133de] description = "both hands have a flush, tie goes to high card, down to the last one if necessary" +include = false + +[e04137c5-c19a-4dfc-97a1-9dfe9baaa2ff] +description = "both hands have a flush, tie goes to high card, down to the last one if necessary" +reimplements = "4d90261d-251c-49bd-a468-896bf10133de" [3a19361d-8974-455c-82e5-f7152f5dba7c] description = "full house beats a flush" @@ -90,5 +115,17 @@ description = "with multiple decks, both hands with identical four of a kind, ti [923bd910-dc7b-4f7d-a330-8b42ec10a3ac] description = "straight flush beats four of a kind" +[d9629e22-c943-460b-a951-2134d1b43346] +description = "aces can end a straight flush (10 J Q K A)" + +[05d5ede9-64a5-4678-b8ae-cf4c595dc824] +description = "aces can start a straight flush (A 2 3 4 5)" + +[ad655466-6d04-49e8-a50c-0043c3ac18ff] +description = "aces cannot be in the middle of a straight flush (Q K A 2 3)" + [d0927f70-5aec-43db-aed8-1cbd1b6ee9ad] -description = "both hands have straight flush, tie goes to highest-ranked card" +description = "both hands have a straight flush, tie goes to highest-ranked card" + +[be620e09-0397-497b-ac37-d1d7a4464cfc] +description = "even though an ace is usually high, a 5-high straight flush is the lowest-scoring straight flush" diff --git a/exercises/practice/poker/Package.swift b/exercises/practice/poker/Package.swift index 5f46b8cf2..f4670851b 100644 --- a/exercises/practice/poker/Package.swift +++ b/exercises/practice/poker/Package.swift @@ -1,21 +1,21 @@ -// swift-tools-version:5.3 +// swift-tools-version:6.0 import PackageDescription let package = Package( - name: "Poker", - products: [ - .library( - name: "Poker", - targets: ["Poker"]), - ], - dependencies: [], - targets: [ - .target( - name: "Poker", - dependencies: []), - .testTarget( - name: "PokerTests", - dependencies: ["Poker"]), - ] + name: "Poker", + products: [ + .library( + name: "Poker", + targets: ["Poker"]) + ], + dependencies: [], + targets: [ + .target( + name: "Poker", + dependencies: []), + .testTarget( + name: "PokerTests", + dependencies: ["Poker"]), + ] ) diff --git a/exercises/practice/poker/Tests/PokerTests/PokerTests.swift b/exercises/practice/poker/Tests/PokerTests/PokerTests.swift index d6cc8f1e4..fc4ff37db 100644 --- a/exercises/practice/poker/Tests/PokerTests/PokerTests.swift +++ b/exercises/practice/poker/Tests/PokerTests/PokerTests.swift @@ -1,267 +1,325 @@ -import XCTest +import Foundation +import Testing + @testable import Poker -class PokerTests: XCTestCase { - var validTestCases:[(name: String, hands: [String], best: String)] = [] - var invalidTestCases:[(name: String, hand: String)] = [] - - func testInvalidCases() { - for each in invalidTestCases { - XCTAssertNil(PokerHand(each.hand), "\(each.name)") - } - } - - func testAllValid() { - for each in validTestCases { - XCTAssertEqual(Poker.bestHand(each.hands), each.best, "\(each.name)") - } - } - - override func setUp() { - super.setUp() - - validTestCases = [ - ( - name: "single hand is always best", - hands: ["3♡ 10♢ 7♧ 8♤ A♢"], - best: "3♡ 10♢ 7♧ 8♤ A♢" - ), - ( - name: "highest card", - hands: ["3♢ 2♢ 5♤ 6♤ 9♡", "3♡ 2♡ 5♧ 6♢ 10♡"], - best: "3♡ 2♡ 5♧ 6♢ 10♡" - ), - ( - name: "One pair", - hands: ["3♢ 2♢ 5♤ 6♤ 9♡", "3♡ 3♤ 5♧ 6♢ 9♢"], - best: "3♡ 3♤ 5♧ 6♢ 9♢" - ), - ( - name: "pair beats lower", - hands: ["4♢ 3♤ 4♤ J♤ K♤", "A♡ K♡ J♢ 10♧ 9♡"], - best: "4♢ 3♤ 4♤ J♤ K♤" - ), - ( - name: "best pair", - hands: ["4♡ 2♡ 5♧ 4♢ 10♡", "3♢ 3♡ 5♤ 6♤ 9♡"], - best: "4♡ 2♡ 5♧ 4♢ 10♡" - ), - ( - name: "best pair with same pair and highest cards", - hands: ["4♡ 2♡ 5♧ 4♢ 10♡", "4♤ 4♧ 5♡ 10♢ 3♡"], - best: "4♤ 4♧ 5♡ 10♢ 3♡" - ), - ( - name: "two pair beats lower", - hands: [ - "4♢ 3♤ 4♤ J♤ K♤", - "A♡ K♡ J♢ 10♧ 9♡", - "2♢ 8♡ 5♢ 2♡ 8♧" - ], - best: "2♢ 8♡ 5♢ 2♡ 8♧" - ), - ( - name: "best two pair", - hands: [ - "4♢ J♧ 4♤ J♤ K♤", - "A♡ K♡ J♢ 10♧ 9♡", - "2♢ 8♡ 5♢ 2♡ 8♧" - ], - best: "4♢ J♧ 4♤ J♤ K♤" - ), - ( - name: "best two pair with equal highest pair", - hands: [ - "4♢ J♧ 4♤ J♤ K♤", - "A♡ K♡ J♢ 10♧ 9♡", - "3♢ J♡ 5♢ 3♡ J♢" - ], - best: "4♢ J♧ 4♤ J♤ K♤" - ), - ( - name: "best two pair with equal pairs", - hands: [ - "4♢ J♧ 4♤ J♤ 2♤", - "A♡ K♡ J♢ 10♧ 9♡", - "4♧ J♡ 5♢ 4♡ J♢" - ], - best: "4♧ J♡ 5♢ 4♡ J♢" - ), - ( - name: "full house", - hands: [ - "4♢ 3♤ 4♤ J♤ K♤", - "A♡ K♡ J♢ 10♧ 9♡", - "3♡ 8♡ 3♢ 3♧ 8♧", - "2♢ 8♡ 5♢ 2♡ 8♧" - ], - best: "3♡ 8♡ 3♢ 3♧ 8♧" - ), - ( - name: "best three of a kind", - hands: [ - "4♢ 3♤ 4♤ J♤ 4♡", - "A♡ K♡ J♢ 10♧ 9♡", - "3♢ 8♡ 3♡ 3♧ 9♧", - "2♢ 8♡ 5♢ 2♡ 8♧" - ], - best: "4♢ 3♤ 4♤ J♤ 4♡" - ), - ( - name: "straight beats lower", - hands: [ - "4♢ 3♤ 4♤ J♤ K♤", - "Q♡ K♡ J♢ 10♧ 9♡", - "3♡ 8♡ 3♢ 3♧ 9♧", - "2♢ 8♡ 5♢ 2♡ 8♧" - ], - best: "Q♡ K♡ J♢ 10♧ 9♡" - ), - ( - name: "straight includes ace as one", - hands: [ - "4♢ 3♤ 4♤ J♤ K♤", - "2♤ 3♡ A♤ 5♤ 4♤", - "3♢ 8♡ 3♡ 3♧ 9♧", - "2♢ 8♡ 5♢ 2♡ 8♧" - ], - best: "2♤ 3♡ A♤ 5♤ 4♤" - ), - ( - name: "best straight", - hands: [ - "4♢ 3♤ 4♤ J♤ K♤", - "Q♡ K♡ J♢ 10♧ 9♡", - "A♢ K♧ 10♢ J♢ Q♢", - "2♢ 8♡ 5♢ 2♡ 8♧" - ], - best: "A♢ K♧ 10♢ J♢ Q♢" - ), - ( - name: "flush beats lower", - hands: [ - "4♤ 3♤ 8♤ J♤ K♤", - "Q♡ K♡ J♢ 10♧ 9♡", - "3♢ 8♡ 3♢ 3♧ 9♧", - "2♢ 8♡ 5♢ 2♡ 8♧" - ], - best: "4♤ 3♤ 8♤ J♤ K♤" - ), - ( - name: "best flush", - hands: [ - "4♤ 3♤ 8♤ J♤ K♤", - "Q♡ K♡ J♢ 10♧ 9♡", - "3♢ 8♢ A♢ 2♢ 7♢", - "2♢ 8♡ 5♢ 2♡ 8♧" - ], - best: "3♢ 8♢ A♢ 2♢ 7♢" - ), - ( - name: "full house beats lower", - hands: [ - "4♤ 3♤ 8♤ J♤ K♤", - "2♢ 8♡ 8♢ 2♡ 8♧", - "Q♡ K♡ J♢ 10♧ 9♡", - "3♡ A♡ 3♢ 3♧ A♧" - ], - best: "2♢ 8♡ 8♢ 2♡ 8♧" - ), - ( - name: "best full house", - hands: [ - "4♤ 3♤ 8♤ J♤ K♤", - "2♢ 8♡ 8♢ 2♡ 8♧", - "5♡ 5♢ A♤ 5♧ A♢", - "3♡ A♡ 3♢ 3♧ A♧" - ], - best: "2♢ 8♡ 8♢ 2♡ 8♧" - ), - ( - name: "four of a kind beats lower", - hands: [ - "4♤ 5♤ 8♤ J♤ K♤", - "2♢ 8♡ 8♢ 2♡ 8♧", - "Q♡ K♡ J♢ 10♧ 9♡", - "3♢ 3♡ 3♤ 3♧ A♧" - ], - best: "3♢ 3♡ 3♤ 3♧ A♧" - ), - ( - name: "best four of a kind", - hands: [ - "4♤ 5♤ 8♤ J♤ K♤", - "2♢ 2♧ 8♢ 2♡ 2♤", - "Q♡ K♡ J♢ 10♧ 9♡", - "3♢ 3♡ 3♤ 3♧ A♧" - ], - best: "3♢ 3♡ 3♤ 3♧ A♧" - ), - ( - name: "straight flush beats lower", - hands: [ - "4♤ 4♢ 4♡ 4♧ K♤", - "2♢ 8♡ 8♢ 2♡ 8♧", - "Q♡ K♡ 8♡ 10♡ 9♡", - "2♤ 3♤ A♤ 5♤ 4♤" - ], - best: "2♤ 3♤ A♤ 5♤ 4♤" - ), - ( - name: "best straight flush is royal flush", - hands: [ - "4♤ 5♤ 8♤ J♤ K♤", - "2♢ 8♡ 8♢ 2♡ 8♧", - "Q♡ K♡ J♡ 10♡ 9♡", - "Q♢ K♢ J♢ 10♢ A♢" - ], - best: "Q♢ K♢ J♢ 10♢ A♢" - ) - ] - - invalidTestCases = - [ - ( - name: "1 is an invalid card rank", - hand: "1♢ 2♡ 3♡ 4♡ 5♡" - ), - ( - name: "15 is an invalid card rank", - hand: "15♢ 2♡ 3♡ 4♡ 5♡" - ), - ( - name: "too few cards", - hand: "2♡ 3♡ 4♡ 5♡" - ), - ( - name: "too many cards", - hand: "2♡ 3♡ 4♡ 5♡ 6♡ 7♡" - ), - ( - name: "lack of rank", - hand: "11♢ 2♡ ♡ 4♡ 5♡" - ), - ( - name: "lack of suit", - hand: "2♡ 3♡ 4 5♡ 7♡" - ), - ( - name: "H is an invalid suit", - hand: "2♡ 3♡ 4H 5♡ 7♡" - ), - ( - name: "♥ is an invalid suit", - hand: "2♡ 3♡ 4♥ 5♡ 7♡" - ), - ( - name: "lack of spacing", - hand: "2♡ 3♡ 5♡7♡ 8♡" - ), - ( - name: "double suits after rank", - hand: "2♡ 3♡ 5♡♡ 8♡ 9♡" - ) - ] - - } +let RUNALL = Bool(ProcessInfo.processInfo.environment["RUNALL", default: "true"]) ?? false + +@Suite struct PokerTests { + + @Test("single hand always wins") + func testSingleHandAlwaysWins() { + let poker = Poker(["4S 5S 7H 8D JC"]) + let bestHand = poker.bestHands() + let expected = "4S 5S 7H 8D JC" + #expect(bestHand == expected) + } + + @Test("highest card out of all hands wins", .enabled(if: RUNALL)) + func testHighestCardOutOfAllHandsWins() { + let poker = Poker(["4D 5S 6S 8D 3C", "2S 4C 7S 9H 10H", "3S 4S 5D 6H JH"]) + let bestHand = poker.bestHands() + let expected = "3S 4S 5D 6H JH" + #expect(bestHand == expected) + } + + @Test("a tie has multiple winners", .enabled(if: RUNALL)) + func testATieHasMultipleWinners() { + let poker = Poker(["4D 5S 6S 8D 3C", "2S 4C 7S 9H 10H", "3S 4S 5D 6H JH", "3H 4H 5C 6C JD"]) + let bestHand = poker.bestHands() + let expected = "3S 4S 5D 6H JH" + #expect(bestHand == expected) + } + + @Test( + "multiple hands with the same high cards, tie compares next highest ranked, down to last card", + .enabled(if: RUNALL)) + func testMultipleHandsWithTheSameHighCardsTieComparesNextHighestRankedDownToLastCard() { + let poker = Poker(["3S 5H 6S 8D 7H", "2S 5D 6D 8C 7S"]) + let bestHand = poker.bestHands() + let expected = "3S 5H 6S 8D 7H" + #expect(bestHand == expected) + } + + @Test("winning high card hand also has the lowest card", .enabled(if: RUNALL)) + func testWinningHighCardHandAlsoHasTheLowestCard() { + let poker = Poker(["2S 5H 6S 8D 7H", "3S 4D 6D 8C 7S"]) + let bestHand = poker.bestHands() + let expected = "2S 5H 6S 8D 7H" + #expect(bestHand == expected) + } + + @Test("one pair beats high card", .enabled(if: RUNALL)) + func testOnePairBeatsHighCard() { + let poker = Poker(["4S 5H 6C 8D KH", "2S 4H 6S 4D JH"]) + let bestHand = poker.bestHands() + let expected = "2S 4H 6S 4D JH" + #expect(bestHand == expected) + } + + @Test("highest pair wins", .enabled(if: RUNALL)) + func testHighestPairWins() { + let poker = Poker(["4S 2H 6S 2D JH", "2S 4H 6C 4D JD"]) + let bestHand = poker.bestHands() + let expected = "2S 4H 6C 4D JD" + #expect(bestHand == expected) + } + + @Test("both hands have the same pair, high card wins", .enabled(if: RUNALL)) + func testBothHandsHaveTheSamePairHighCardWins() { + let poker = Poker(["4H 4S AH JC 3D", "4C 4D AS 5D 6C"]) + let bestHand = poker.bestHands() + let expected = "4H 4S AH JC 3D" + #expect(bestHand == expected) + } + + @Test("two pairs beats one pair", .enabled(if: RUNALL)) + func testTwoPairsBeatsOnePair() { + let poker = Poker(["2S 8H 6S 8D JH", "4S 5H 4C 8C 5C"]) + let bestHand = poker.bestHands() + let expected = "4S 5H 4C 8C 5C" + #expect(bestHand == expected) + } + + @Test("both hands have two pairs, highest ranked pair wins", .enabled(if: RUNALL)) + func testBothHandsHaveTwoPairsHighestRankedPairWins() { + let poker = Poker(["2S 8H 2D 8D 3H", "4S 5H 4C 8S 5D"]) + let bestHand = poker.bestHands() + let expected = "2S 8H 2D 8D 3H" + #expect(bestHand == expected) + } + + @Test( + "both hands have two pairs, with the same highest ranked pair, tie goes to low pair", + .enabled(if: RUNALL)) + func testBothHandsHaveTwoPairsWithTheSameHighestRankedPairTieGoesToLowPair() { + let poker = Poker(["2S QS 2C QD JH", "JD QH JS 8D QC"]) + let bestHand = poker.bestHands() + let expected = "JD QH JS 8D QC" + #expect(bestHand == expected) + } + + @Test( + "both hands have two identically ranked pairs, tie goes to remaining card (kicker)", + .enabled(if: RUNALL)) + func testBothHandsHaveTwoIdenticallyRankedPairsTieGoesToRemainingCardKicker() { + let poker = Poker(["JD QH JS 8D QC", "JS QS JC 2D QD"]) + let bestHand = poker.bestHands() + let expected = "JD QH JS 8D QC" + #expect(bestHand == expected) + } + + @Test( + "both hands have two pairs that add to the same value, win goes to highest pair", + .enabled(if: RUNALL)) + func testBothHandsHaveTwoPairsThatAddToTheSameValueWinGoesToHighestPair() { + let poker = Poker(["6S 6H 3S 3H AS", "7H 7S 2H 2S AC"]) + let bestHand = poker.bestHands() + let expected = "7H 7S 2H 2S AC" + #expect(bestHand == expected) + } + + @Test("two pairs first ranked by largest pair", .enabled(if: RUNALL)) + func testTwoPairsFirstRankedByLargestPair() { + let poker = Poker(["5C 2S 5S 4H 4C", "6S 2S 6H 7C 2C"]) + let bestHand = poker.bestHands() + let expected = "6S 2S 6H 7C 2C" + #expect(bestHand == expected) + } + + @Test("three of a kind beats two pair", .enabled(if: RUNALL)) + func testThreeOfAKindBeatsTwoPair() { + let poker = Poker(["2S 8H 2H 8D JH", "4S 5H 4C 8S 4H"]) + let bestHand = poker.bestHands() + let expected = "4S 5H 4C 8S 4H" + #expect(bestHand == expected) + } + + @Test("both hands have three of a kind, tie goes to highest ranked triplet", .enabled(if: RUNALL)) + func testBothHandsHaveThreeOfAKindTieGoesToHighestRankedTriplet() { + let poker = Poker(["2S 2H 2C 8D JH", "4S AH AS 8C AD"]) + let bestHand = poker.bestHands() + let expected = "4S AH AS 8C AD" + #expect(bestHand == expected) + } + + @Test( + "with multiple decks, two players can have same three of a kind, ties go to highest remaining cards", + .enabled(if: RUNALL)) + func testWithMultipleDecksTwoPlayersCanHaveSameThreeOfAKindTiesGoToHighestRemainingCards() { + let poker = Poker(["5S AH AS 7C AD", "4S AH AS 8C AD"]) + let bestHand = poker.bestHands() + let expected = "4S AH AS 8C AD" + #expect(bestHand == expected) + } + + @Test("a straight beats three of a kind", .enabled(if: RUNALL)) + func testAStraightBeatsThreeOfAKind() { + let poker = Poker(["4S 5H 4C 8D 4H", "3S 4D 2S 6D 5C"]) + let bestHand = poker.bestHands() + let expected = "3S 4D 2S 6D 5C" + #expect(bestHand == expected) + } + + @Test("aces can end a straight (10 J Q K A)", .enabled(if: RUNALL)) + func testAcesCanEndAStraight10JQKA() { + let poker = Poker(["4S 5H 4C 8D 4H", "10D JH QS KD AC"]) + let bestHand = poker.bestHands() + let expected = "10D JH QS KD AC" + #expect(bestHand == expected) + } + + @Test("aces can start a straight (A 2 3 4 5)", .enabled(if: RUNALL)) + func testAcesCanStartAStraightA2345() { + let poker = Poker(["4S 5H 4C 8D 4H", "4D AH 3S 2D 5C"]) + let bestHand = poker.bestHands() + let expected = "4D AH 3S 2D 5C" + #expect(bestHand == expected) + } + + @Test("aces cannot be in the middle of a straight (Q K A 2 3)", .enabled(if: RUNALL)) + func testAcesCannotBeInTheMiddleOfAStraightQKA23() { + let poker = Poker(["2C 3D 7H 5H 2S", "QS KH AC 2D 3S"]) + let bestHand = poker.bestHands() + let expected = "2C 3D 7H 5H 2S" + #expect(bestHand == expected) + } + + @Test("both hands with a straight, tie goes to highest ranked card", .enabled(if: RUNALL)) + func testBothHandsWithAStraightTieGoesToHighestRankedCard() { + let poker = Poker(["4S 6C 7S 8D 5H", "5S 7H 8S 9D 6H"]) + let bestHand = poker.bestHands() + let expected = "5S 7H 8S 9D 6H" + #expect(bestHand == expected) + } + + @Test( + "even though an ace is usually high, a 5-high straight is the lowest-scoring straight", + .enabled(if: RUNALL)) + func testEvenThoughAnAceIsUsuallyHighA5HighStraightIsTheLowestScoringStraight() { + let poker = Poker(["2H 3C 4D 5D 6H", "4S AH 3S 2D 5H"]) + let bestHand = poker.bestHands() + let expected = "2H 3C 4D 5D 6H" + #expect(bestHand == expected) + } + + @Test("flush beats a straight", .enabled(if: RUNALL)) + func testFlushBeatsAStraight() { + let poker = Poker(["4C 6H 7D 8D 5H", "2S 4S 5S 6S 7S"]) + let bestHand = poker.bestHands() + let expected = "2S 4S 5S 6S 7S" + #expect(bestHand == expected) + } + + @Test( + "both hands have a flush, tie goes to high card, down to the last one if necessary", + .enabled(if: RUNALL)) + func testBothHandsHaveAFlushTieGoesToHighCardDownToTheLastOneIfNecessary() { + let poker = Poker(["2H 7H 8H 9H 6H", "3S 5S 6S 7S 8S"]) + let bestHand = poker.bestHands() + let expected = "2H 7H 8H 9H 6H" + #expect(bestHand == expected) + } + + @Test("full house beats a flush", .enabled(if: RUNALL)) + func testFullHouseBeatsAFlush() { + let poker = Poker(["3H 6H 7H 8H 5H", "4S 5H 4C 5D 4H"]) + let bestHand = poker.bestHands() + let expected = "4S 5H 4C 5D 4H" + #expect(bestHand == expected) + } + + @Test("both hands have a full house, tie goes to highest-ranked triplet", .enabled(if: RUNALL)) + func testBothHandsHaveAFullHouseTieGoesToHighestRankedTriplet() { + let poker = Poker(["4H 4S 4D 9S 9D", "5H 5S 5D 8S 8D"]) + let bestHand = poker.bestHands() + let expected = "5H 5S 5D 8S 8D" + #expect(bestHand == expected) + } + + @Test( + "with multiple decks, both hands have a full house with the same triplet, tie goes to the pair", + .enabled(if: RUNALL)) + func testWithMultipleDecksBothHandsHaveAFullHouseWithTheSameTripletTieGoesToThePair() { + let poker = Poker(["5H 5S 5D 9S 9D", "5H 5S 5D 8S 8D"]) + let bestHand = poker.bestHands() + let expected = "5H 5S 5D 9S 9D" + #expect(bestHand == expected) + } + + @Test("four of a kind beats a full house", .enabled(if: RUNALL)) + func testFourOfAKindBeatsAFullHouse() { + let poker = Poker(["4S 5H 4D 5D 4H", "3S 3H 2S 3D 3C"]) + let bestHand = poker.bestHands() + let expected = "3S 3H 2S 3D 3C" + #expect(bestHand == expected) + } + + @Test("both hands have four of a kind, tie goes to high quad", .enabled(if: RUNALL)) + func testBothHandsHaveFourOfAKindTieGoesToHighQuad() { + let poker = Poker(["2S 2H 2C 8D 2D", "4S 5H 5S 5D 5C"]) + let bestHand = poker.bestHands() + let expected = "4S 5H 5S 5D 5C" + #expect(bestHand == expected) + } + + @Test( + "with multiple decks, both hands with identical four of a kind, tie determined by kicker", + .enabled(if: RUNALL)) + func testWithMultipleDecksBothHandsWithIdenticalFourOfAKindTieDeterminedByKicker() { + let poker = Poker(["3S 3H 2S 3D 3C", "3S 3H 4S 3D 3C"]) + let bestHand = poker.bestHands() + let expected = "3S 3H 4S 3D 3C" + #expect(bestHand == expected) + } + + @Test("straight flush beats four of a kind", .enabled(if: RUNALL)) + func testStraightFlushBeatsFourOfAKind() { + let poker = Poker(["4S 5H 5S 5D 5C", "7S 8S 9S 6S 10S"]) + let bestHand = poker.bestHands() + let expected = "7S 8S 9S 6S 10S" + #expect(bestHand == expected) + } + + @Test("aces can end a straight flush (10 J Q K A)", .enabled(if: RUNALL)) + func testAcesCanEndAStraightFlush10JQKA() { + let poker = Poker(["KC AH AS AD AC", "10C JC QC KC AC"]) + let bestHand = poker.bestHands() + let expected = "10C JC QC KC AC" + #expect(bestHand == expected) + } + + @Test("aces can start a straight flush (A 2 3 4 5)", .enabled(if: RUNALL)) + func testAcesCanStartAStraightFlushA2345() { + let poker = Poker(["KS AH AS AD AC", "4H AH 3H 2H 5H"]) + let bestHand = poker.bestHands() + let expected = "4H AH 3H 2H 5H" + #expect(bestHand == expected) + } + + @Test("aces cannot be in the middle of a straight flush (Q K A 2 3)", .enabled(if: RUNALL)) + func testAcesCannotBeInTheMiddleOfAStraightFlushQKA23() { + let poker = Poker(["2C AC QC 10C KC", "QH KH AH 2H 3H"]) + let bestHand = poker.bestHands() + let expected = "2C AC QC 10C KC" + #expect(bestHand == expected) + } + + @Test("both hands have a straight flush, tie goes to highest-ranked card", .enabled(if: RUNALL)) + func testBothHandsHaveAStraightFlushTieGoesToHighestRankedCard() { + let poker = Poker(["4H 6H 7H 8H 5H", "5S 7S 8S 9S 6S"]) + let bestHand = poker.bestHands() + let expected = "5S 7S 8S 9S 6S" + #expect(bestHand == expected) + } + + @Test( + "even though an ace is usually high, a 5-high straight flush is the lowest-scoring straight flush", + .enabled(if: RUNALL)) + func testEvenThoughAnAceIsUsuallyHighA5HighStraightFlushIsTheLowestScoringStraightFlush() { + let poker = Poker(["2H 3H 4H 5H 6H", "4D AD 3D 2D 5D"]) + let bestHand = poker.bestHands() + let expected = "2H 3H 4H 5H 6H" + #expect(bestHand == expected) + } } diff --git a/exercises/practice/saddle-points/.meta/Sources/SaddlePoints/Position.swift b/exercises/practice/saddle-points/.meta/Sources/SaddlePoints/Position.swift new file mode 100644 index 000000000..bd74c7fe6 --- /dev/null +++ b/exercises/practice/saddle-points/.meta/Sources/SaddlePoints/Position.swift @@ -0,0 +1,8 @@ +struct Position : Equatable { + let row: Int + let column: Int + + static func ==(lhs: Position, rhs: Position) -> Bool { + return lhs.row == rhs.row && lhs.column == rhs.column + } +} diff --git a/exercises/practice/saddle-points/.meta/Sources/SaddlePoints/SaddlePointsExample.swift b/exercises/practice/saddle-points/.meta/Sources/SaddlePoints/SaddlePointsExample.swift index ccaf19877..7542b6515 100644 --- a/exercises/practice/saddle-points/.meta/Sources/SaddlePoints/SaddlePointsExample.swift +++ b/exercises/practice/saddle-points/.meta/Sources/SaddlePoints/SaddlePointsExample.swift @@ -1,48 +1,20 @@ -struct SaddlePointsMatrix { - - let rows: [[Int]] - let columns: [[Int]] - let saddlePoints: [[Int]] - - init(_ matrix: String) { - var rows = [[Int]]() - - let rowItems = matrix.split(separator: "\n").map { String($0) } - - for row in rowItems { - let rowItems = row.split(separator: " ").map { Int(String($0)) ?? 0 } - rows.append(rowItems) - } - - self.rows = rows - - var columns = [[Int]]() - - let count = rows[0].count - for i in 0.. [Position] { + var saddlePoints = [Position]() + for (rowIndex, row) in matrix.enumerated() { + for (columnIndex, element) in row.enumerated() { + if isSaddlePoint(matrix, rowIndex, columnIndex) { + saddlePoints.append(Position(row: rowIndex + 1, column: columnIndex + 1)) } } } - - self.saddlePoints = saddlePoints + return saddlePoints } + static private func isSaddlePoint(_ matrix: [[Int]], _ rowIndex: Int, _ columnIndex: Int) -> Bool { + let element = matrix[rowIndex][columnIndex] + let row = matrix[rowIndex] + let column = matrix.map { $0[columnIndex] } + return row.allSatisfy { $0 <= element } && column.allSatisfy { $0 >= element } + } } diff --git a/exercises/practice/saddle-points/.meta/config.json b/exercises/practice/saddle-points/.meta/config.json index f43cfbbbe..8b791aff9 100644 --- a/exercises/practice/saddle-points/.meta/config.json +++ b/exercises/practice/saddle-points/.meta/config.json @@ -18,6 +18,9 @@ ], "example": [ ".meta/Sources/SaddlePoints/SaddlePointsExample.swift" + ], + "editor": [ + "Sources/SaddlePoints/Position.swift" ] }, "blurb": "Detect saddle points in a matrix.", diff --git a/exercises/practice/saddle-points/.meta/template.swift b/exercises/practice/saddle-points/.meta/template.swift new file mode 100644 index 000000000..3acfe075d --- /dev/null +++ b/exercises/practice/saddle-points/.meta/template.swift @@ -0,0 +1,31 @@ +import Testing +import Foundation +@testable import {{exercise|camelCase}} + +let RUNALL = Bool(ProcessInfo.processInfo.environment["RUNALL", default: "false"]) ?? false + +@Suite struct {{exercise|camelCase}}Tests { + {% for case in cases %} + {% if forloop.first -%} + @Test("{{case.description}}") + {% else -%} + @Test("{{case.description}}", .enabled(if: RUNALL)) + {% endif -%} + func test{{case.description |camelCase }}() { + {% if case.input.matrix[0] -%} + let input = {{case.input.matrix}} + {%- else -%} + let input = [[Int]]() + {%- endif %} + let saddlePoints = {{exercise|camelCase}}.{{case.property}}(input).sorted { $0.row < $1.row || $0.row == $1.row && $0.column > $1.column } + let expected : [Position] = [ + {% for point in case.expected -%} + Position(row: {{point.row}}, column: {{point.column}}), + {%- endfor %} + ].sorted { + $0.row < $1.row || $0.row == $1.row && $0.column > $1.column + } + #expect(saddlePoints == expected) + } +{% endfor -%} +} \ No newline at end of file diff --git a/exercises/practice/saddle-points/Package.swift b/exercises/practice/saddle-points/Package.swift index f4d1e7f63..be2ec0521 100644 --- a/exercises/practice/saddle-points/Package.swift +++ b/exercises/practice/saddle-points/Package.swift @@ -1,4 +1,4 @@ -// swift-tools-version:5.3 +// swift-tools-version:6.0 import PackageDescription diff --git a/exercises/practice/saddle-points/Sources/SaddlePoints/Position.swift b/exercises/practice/saddle-points/Sources/SaddlePoints/Position.swift new file mode 100644 index 000000000..bd74c7fe6 --- /dev/null +++ b/exercises/practice/saddle-points/Sources/SaddlePoints/Position.swift @@ -0,0 +1,8 @@ +struct Position : Equatable { + let row: Int + let column: Int + + static func ==(lhs: Position, rhs: Position) -> Bool { + return lhs.row == rhs.row && lhs.column == rhs.column + } +} diff --git a/exercises/practice/saddle-points/Tests/SaddlePointsTests/SaddlePointsTests.swift b/exercises/practice/saddle-points/Tests/SaddlePointsTests/SaddlePointsTests.swift index 8f7fbd0f3..99f332e57 100644 --- a/exercises/practice/saddle-points/Tests/SaddlePointsTests/SaddlePointsTests.swift +++ b/exercises/practice/saddle-points/Tests/SaddlePointsTests/SaddlePointsTests.swift @@ -1,60 +1,135 @@ -import XCTest +import Foundation +import Testing + @testable import SaddlePoints -private extension XCTest { - func XCTAssertEqualMultiArray(_ aArray1: [[Int]], _ aArray2: [[Int]]) { - XCTAssertEqual(Array(aArray1.joined()), Array(aArray2.joined())) - } -} +let RUNALL = Bool(ProcessInfo.processInfo.environment["RUNALL", default: "true"]) ?? false -class SaddlePointsTests: XCTestCase { - func testExtractARow() { - let matrix = SaddlePointsMatrix("1 2\n10 20") - XCTAssertEqual([1, 2], matrix.rows[0]) - } +@Suite struct SaddlePointsTests { - func testExtractSameRowAgain() { - let matrix = SaddlePointsMatrix("9 7\n8 6") - XCTAssertEqual([9, 7], matrix.rows[0]) + @Test("Can identify single saddle point") + func testCanIdentifySingleSaddlePoint() { + let input = [[9, 8, 7], [5, 3, 2], [6, 6, 7]] + let saddlePoints = SaddlePoints.saddlePoints(input).sorted { + $0.row < $1.row || $0.row == $1.row && $0.column > $1.column } + let expected: [Position] = [ + Position(row: 2, column: 1) + ].sorted { + $0.row < $1.row || $0.row == $1.row && $0.column > $1.column + } + #expect(saddlePoints == expected) + } - func testExtractOtherRow() { - let matrix = SaddlePointsMatrix("9 8 7\n19 18 17") - XCTAssertEqual([19, 18, 17], matrix.rows[1]) + @Test("Can identify that empty matrix has no saddle points", .enabled(if: RUNALL)) + func testCanIdentifyThatEmptyMatrixHasNoSaddlePoints() { + let input = [[Int]]() + let saddlePoints = SaddlePoints.saddlePoints(input).sorted { + $0.row < $1.row || $0.row == $1.row && $0.column > $1.column + } + let expected: [Position] = [].sorted { + $0.row < $1.row || $0.row == $1.row && $0.column > $1.column } + #expect(saddlePoints == expected) + } - func testExtractOtherRowAgain() { - let matrix = SaddlePointsMatrix("1 4 9\n16 25 36") - XCTAssertEqual([16, 25, 36], matrix.rows[1]) + @Test("Can identify lack of saddle points when there are none", .enabled(if: RUNALL)) + func testCanIdentifyLackOfSaddlePointsWhenThereAreNone() { + let input = [[1, 2, 3], [3, 1, 2], [2, 3, 1]] + let saddlePoints = SaddlePoints.saddlePoints(input).sorted { + $0.row < $1.row || $0.row == $1.row && $0.column > $1.column + } + let expected: [Position] = [].sorted { + $0.row < $1.row || $0.row == $1.row && $0.column > $1.column } + #expect(saddlePoints == expected) + } - func testExtractAColumn() { - let matrix = SaddlePointsMatrix("1 2 3\n4 5 6\n7 8 9\n 8 7 6") - XCTAssertEqual([1, 4, 7, 8], matrix.columns[0]) + @Test("Can identify multiple saddle points in a column", .enabled(if: RUNALL)) + func testCanIdentifyMultipleSaddlePointsInAColumn() { + let input = [[4, 5, 4], [3, 5, 5], [1, 5, 4]] + let saddlePoints = SaddlePoints.saddlePoints(input).sorted { + $0.row < $1.row || $0.row == $1.row && $0.column > $1.column } + let expected: [Position] = [ + Position(row: 1, column: 2), Position(row: 2, column: 2), Position(row: 3, column: 2), + ].sorted { + $0.row < $1.row || $0.row == $1.row && $0.column > $1.column + } + #expect(saddlePoints == expected) + } - func testExtractAnotherColumn() { - let matrix = SaddlePointsMatrix("89 1903 3\n18 3 1\n9 4 800") - XCTAssertEqual([1903, 3, 4], matrix.columns[1]) + @Test("Can identify multiple saddle points in a row", .enabled(if: RUNALL)) + func testCanIdentifyMultipleSaddlePointsInARow() { + let input = [[6, 7, 8], [5, 5, 5], [7, 5, 6]] + let saddlePoints = SaddlePoints.saddlePoints(input).sorted { + $0.row < $1.row || $0.row == $1.row && $0.column > $1.column + } + let expected: [Position] = [ + Position(row: 2, column: 1), Position(row: 2, column: 2), Position(row: 2, column: 3), + ].sorted { + $0.row < $1.row || $0.row == $1.row && $0.column > $1.column } + #expect(saddlePoints == expected) + } - func testNoSaddlePoint() { - let matrix = SaddlePointsMatrix("2 1\n1 2") - XCTAssertEqualMultiArray([[Int]()], matrix.saddlePoints) + @Test("Can identify saddle point in bottom right corner", .enabled(if: RUNALL)) + func testCanIdentifySaddlePointInBottomRightCorner() { + let input = [[8, 7, 9], [6, 7, 6], [3, 2, 5]] + let saddlePoints = SaddlePoints.saddlePoints(input).sorted { + $0.row < $1.row || $0.row == $1.row && $0.column > $1.column + } + let expected: [Position] = [ + Position(row: 3, column: 3) + ].sorted { + $0.row < $1.row || $0.row == $1.row && $0.column > $1.column } + #expect(saddlePoints == expected) + } - func testASaddlePoint() { - let matrix = SaddlePointsMatrix("1 2\n3 4") - XCTAssertEqualMultiArray([[0, 1]], matrix.saddlePoints) + @Test("Can identify saddle points in a non square matrix", .enabled(if: RUNALL)) + func testCanIdentifySaddlePointsInANonSquareMatrix() { + let input = [[3, 1, 3], [3, 2, 4]] + let saddlePoints = SaddlePoints.saddlePoints(input).sorted { + $0.row < $1.row || $0.row == $1.row && $0.column > $1.column } + let expected: [Position] = [ + Position(row: 1, column: 3), Position(row: 1, column: 1), + ].sorted { + $0.row < $1.row || $0.row == $1.row && $0.column > $1.column + } + #expect(saddlePoints == expected) + } - func testAnotherSaddlePoint() { - let matrix = SaddlePointsMatrix("18 3 39 19 91\n38 10 8 77 320\n3 4 8 6 7") - XCTAssertEqualMultiArray([[2, 2]], matrix.saddlePoints) + @Test( + "Can identify that saddle points in a single column matrix are those with the minimum value", + .enabled(if: RUNALL)) + func testCanIdentifyThatSaddlePointsInASingleColumnMatrixAreThoseWithTheMinimumValue() { + let input = [[2], [1], [4], [1]] + let saddlePoints = SaddlePoints.saddlePoints(input).sorted { + $0.row < $1.row || $0.row == $1.row && $0.column > $1.column + } + let expected: [Position] = [ + Position(row: 2, column: 1), Position(row: 4, column: 1), + ].sorted { + $0.row < $1.row || $0.row == $1.row && $0.column > $1.column } + #expect(saddlePoints == expected) + } - func testMultipleSaddlePoints() { - let matrix = SaddlePointsMatrix("4 5 4\n3 5 5\n1 5 4") - XCTAssertEqualMultiArray([[0, 1], [1, 1], [2, 1]], matrix.saddlePoints) + @Test( + "Can identify that saddle points in a single row matrix are those with the maximum value", + .enabled(if: RUNALL)) + func testCanIdentifyThatSaddlePointsInASingleRowMatrixAreThoseWithTheMaximumValue() { + let input = [[2, 5, 3, 5]] + let saddlePoints = SaddlePoints.saddlePoints(input).sorted { + $0.row < $1.row || $0.row == $1.row && $0.column > $1.column + } + let expected: [Position] = [ + Position(row: 1, column: 2), Position(row: 1, column: 4), + ].sorted { + $0.row < $1.row || $0.row == $1.row && $0.column > $1.column } + #expect(saddlePoints == expected) + } } diff --git a/generator/Sources/Generator/generator-plugins.swift b/generator/Sources/Generator/generator-plugins.swift index 353bd95bd..bd7d247fa 100644 --- a/generator/Sources/Generator/generator-plugins.swift +++ b/generator/Sources/Generator/generator-plugins.swift @@ -244,6 +244,26 @@ class GeneratorPlugins { return "// Something else ..." } + ext.registerFilter("complexNumber") { (value: Any?) in + if let input = value as? String { + switch input { + case "pi": + return "Double.pi" + case "e": + return "exp(1)" + case "ln(2)": + return "log(2)" + case "ln(2)/2": + return "log(2)/2" + case "pi/4": + return "Double.pi/4" + default: + return input + } + } + return value + } + let environment = Environment(extensions: [ext]) return environment } From 93a1df0e3bee5205f264e97fe195fb6014850900 Mon Sep 17 00:00:00 2001 From: meatball Date: Thu, 2 Jan 2025 19:34:46 +0100 Subject: [PATCH 2/5] Format files --- .../ComplexNumbersExample.swift | 101 ++++++++++-------- .../practice/complex-numbers/Package.swift | 42 ++++---- .../.meta/Sources/Poker/PokerExample.swift | 4 +- .../.meta/Sources/SaddlePoints/Position.swift | 12 +-- .../SaddlePoints/SaddlePointsExample.swift | 31 +++--- .../practice/saddle-points/Package.swift | 30 +++--- 6 files changed, 116 insertions(+), 104 deletions(-) diff --git a/exercises/practice/complex-numbers/.meta/Sources/ComplexNumbers/ComplexNumbersExample.swift b/exercises/practice/complex-numbers/.meta/Sources/ComplexNumbers/ComplexNumbersExample.swift index e5a3d23f6..d43c5b28b 100644 --- a/exercises/practice/complex-numbers/.meta/Sources/ComplexNumbers/ComplexNumbersExample.swift +++ b/exercises/practice/complex-numbers/.meta/Sources/ComplexNumbers/ComplexNumbersExample.swift @@ -3,49 +3,58 @@ import Numerics struct ComplexNumbers: Equatable { - var real: Double - var imaginary: Double - - init(realComponent: Double, imaginaryComponent: Double? = 0) { - real = realComponent - imaginary = imaginaryComponent ?? 0 - } - - func add(complexNumber: ComplexNumbers) -> ComplexNumbers { - ComplexNumbers(realComponent: real + complexNumber.real, imaginaryComponent: imaginary + complexNumber.imaginary) - } - - - func sub(complexNumber: ComplexNumbers) -> ComplexNumbers { - ComplexNumbers(realComponent: real - complexNumber.real, imaginaryComponent: imaginary - complexNumber.imaginary) - } - - func mul(complexNumber: ComplexNumbers) -> ComplexNumbers { - ComplexNumbers(realComponent: real * complexNumber.real - imaginary * complexNumber.imaginary, imaginaryComponent: real * complexNumber.imaginary + imaginary * complexNumber.real) - } - - func div(complexNumber: ComplexNumbers) -> ComplexNumbers { - let denominator = complexNumber.real * complexNumber.real + complexNumber.imaginary * complexNumber.imaginary - let realComponent = (real * complexNumber.real + imaginary * complexNumber.imaginary) / denominator - let imaginaryComponent = (imaginary * complexNumber.real - real * complexNumber.imaginary) / denominator - return ComplexNumbers(realComponent: realComponent, imaginaryComponent: imaginaryComponent) - } - - func absolute() -> Double { - sqrt(Double(real * real + imaginary * imaginary)) - } - - func conjugate() -> ComplexNumbers { - ComplexNumbers(realComponent: real, imaginaryComponent: -imaginary) - } - - func exponent() -> ComplexNumbers { - let expReal = exp(Double(real)) * cos(Double(imaginary)) - let expImaginary = exp(Double(real)) * sin(Double(imaginary)) - return ComplexNumbers(realComponent: expReal, imaginaryComponent: expImaginary) - } - - static func == (lhs: ComplexNumbers, rhs: ComplexNumbers) -> Bool { - lhs.real.isApproximatelyEqual(to: rhs.real, absoluteTolerance: 0.0001) && lhs.imaginary.isApproximatelyEqual(to: rhs.imaginary, absoluteTolerance: 0.0001) - } -} \ No newline at end of file + var real: Double + var imaginary: Double + + init(realComponent: Double, imaginaryComponent: Double? = 0) { + real = realComponent + imaginary = imaginaryComponent ?? 0 + } + + func add(complexNumber: ComplexNumbers) -> ComplexNumbers { + ComplexNumbers( + realComponent: real + complexNumber.real, + imaginaryComponent: imaginary + complexNumber.imaginary) + } + + func sub(complexNumber: ComplexNumbers) -> ComplexNumbers { + ComplexNumbers( + realComponent: real - complexNumber.real, + imaginaryComponent: imaginary - complexNumber.imaginary) + } + + func mul(complexNumber: ComplexNumbers) -> ComplexNumbers { + ComplexNumbers( + realComponent: real * complexNumber.real - imaginary * complexNumber.imaginary, + imaginaryComponent: real * complexNumber.imaginary + imaginary * complexNumber.real) + } + + func div(complexNumber: ComplexNumbers) -> ComplexNumbers { + let denominator = + complexNumber.real * complexNumber.real + complexNumber.imaginary * complexNumber.imaginary + let realComponent = + (real * complexNumber.real + imaginary * complexNumber.imaginary) / denominator + let imaginaryComponent = + (imaginary * complexNumber.real - real * complexNumber.imaginary) / denominator + return ComplexNumbers(realComponent: realComponent, imaginaryComponent: imaginaryComponent) + } + + func absolute() -> Double { + sqrt(Double(real * real + imaginary * imaginary)) + } + + func conjugate() -> ComplexNumbers { + ComplexNumbers(realComponent: real, imaginaryComponent: -imaginary) + } + + func exponent() -> ComplexNumbers { + let expReal = exp(Double(real)) * cos(Double(imaginary)) + let expImaginary = exp(Double(real)) * sin(Double(imaginary)) + return ComplexNumbers(realComponent: expReal, imaginaryComponent: expImaginary) + } + + static func == (lhs: ComplexNumbers, rhs: ComplexNumbers) -> Bool { + lhs.real.isApproximatelyEqual(to: rhs.real, absoluteTolerance: 0.0001) + && lhs.imaginary.isApproximatelyEqual(to: rhs.imaginary, absoluteTolerance: 0.0001) + } +} diff --git a/exercises/practice/complex-numbers/Package.swift b/exercises/practice/complex-numbers/Package.swift index 987a426f2..50c3ce2c6 100644 --- a/exercises/practice/complex-numbers/Package.swift +++ b/exercises/practice/complex-numbers/Package.swift @@ -3,24 +3,26 @@ import PackageDescription let package = Package( - name: "ComplexNumbers", - products: [ - .library( - name: "ComplexNumbers", - targets: ["ComplexNumbers"]), - ], - dependencies: [ - .package(url: "https://github.com/apple/swift-numerics", from: "1.0.2"), - ], - targets: [ - .target( - name: "ComplexNumbers", - dependencies: [ - .product(name: "Numerics", package: "swift-numerics"), - ]), - .testTarget( - name: "ComplexNumbersTests", - dependencies: ["ComplexNumbers", - .product(name: "Numerics", package: "swift-numerics"),]), - ] + name: "ComplexNumbers", + products: [ + .library( + name: "ComplexNumbers", + targets: ["ComplexNumbers"]) + ], + dependencies: [ + .package(url: "https://github.com/apple/swift-numerics", from: "1.0.2") + ], + targets: [ + .target( + name: "ComplexNumbers", + dependencies: [ + .product(name: "Numerics", package: "swift-numerics") + ]), + .testTarget( + name: "ComplexNumbersTests", + dependencies: [ + "ComplexNumbers", + .product(name: "Numerics", package: "swift-numerics"), + ]), + ] ) diff --git a/exercises/practice/poker/.meta/Sources/Poker/PokerExample.swift b/exercises/practice/poker/.meta/Sources/Poker/PokerExample.swift index 1708bcd6e..a54e96a31 100644 --- a/exercises/practice/poker/.meta/Sources/Poker/PokerExample.swift +++ b/exercises/practice/poker/.meta/Sources/Poker/PokerExample.swift @@ -126,7 +126,7 @@ class Poker { if rank == .highCard || rank == .straightFlush || rank == .straight || rank == .flush { return hands.max { hand1, hand2 in let isFlush = rank == .straight || rank == .straightFlush - + func highestCard(_ hand: [String]) -> String { return hand.max { card1, card2 in convertValue(card1, isFlush) < convertValue(card2, isFlush) @@ -137,7 +137,7 @@ class Poker { var hand2High = highestCard(hand2) var hand1 = hand1 - var hand2 = hand2 + var hand2 = hand2 while convertValue(hand1High) == convertValue(hand2High) { hand1 = hand1.filter { $0 != hand1High } diff --git a/exercises/practice/saddle-points/.meta/Sources/SaddlePoints/Position.swift b/exercises/practice/saddle-points/.meta/Sources/SaddlePoints/Position.swift index bd74c7fe6..9b9d61cd9 100644 --- a/exercises/practice/saddle-points/.meta/Sources/SaddlePoints/Position.swift +++ b/exercises/practice/saddle-points/.meta/Sources/SaddlePoints/Position.swift @@ -1,8 +1,8 @@ -struct Position : Equatable { - let row: Int - let column: Int +struct Position: Equatable { + let row: Int + let column: Int - static func ==(lhs: Position, rhs: Position) -> Bool { - return lhs.row == rhs.row && lhs.column == rhs.column - } + static func == (lhs: Position, rhs: Position) -> Bool { + return lhs.row == rhs.row && lhs.column == rhs.column + } } diff --git a/exercises/practice/saddle-points/.meta/Sources/SaddlePoints/SaddlePointsExample.swift b/exercises/practice/saddle-points/.meta/Sources/SaddlePoints/SaddlePointsExample.swift index 7542b6515..6b8f8276f 100644 --- a/exercises/practice/saddle-points/.meta/Sources/SaddlePoints/SaddlePointsExample.swift +++ b/exercises/practice/saddle-points/.meta/Sources/SaddlePoints/SaddlePointsExample.swift @@ -1,20 +1,21 @@ struct SaddlePoints { - static func saddlePoints(_ matrix: [[Int]]) -> [Position] { - var saddlePoints = [Position]() - for (rowIndex, row) in matrix.enumerated() { - for (columnIndex, element) in row.enumerated() { - if isSaddlePoint(matrix, rowIndex, columnIndex) { - saddlePoints.append(Position(row: rowIndex + 1, column: columnIndex + 1)) - } - } + static func saddlePoints(_ matrix: [[Int]]) -> [Position] { + var saddlePoints = [Position]() + for (rowIndex, row) in matrix.enumerated() { + for (columnIndex, element) in row.enumerated() { + if isSaddlePoint(matrix, rowIndex, columnIndex) { + saddlePoints.append(Position(row: rowIndex + 1, column: columnIndex + 1)) } - return saddlePoints + } } + return saddlePoints + } - static private func isSaddlePoint(_ matrix: [[Int]], _ rowIndex: Int, _ columnIndex: Int) -> Bool { - let element = matrix[rowIndex][columnIndex] - let row = matrix[rowIndex] - let column = matrix.map { $0[columnIndex] } - return row.allSatisfy { $0 <= element } && column.allSatisfy { $0 >= element } - } + static private func isSaddlePoint(_ matrix: [[Int]], _ rowIndex: Int, _ columnIndex: Int) -> Bool + { + let element = matrix[rowIndex][columnIndex] + let row = matrix[rowIndex] + let column = matrix.map { $0[columnIndex] } + return row.allSatisfy { $0 <= element } && column.allSatisfy { $0 >= element } + } } diff --git a/exercises/practice/saddle-points/Package.swift b/exercises/practice/saddle-points/Package.swift index be2ec0521..d11acafa2 100644 --- a/exercises/practice/saddle-points/Package.swift +++ b/exercises/practice/saddle-points/Package.swift @@ -3,19 +3,19 @@ import PackageDescription let package = Package( - name: "SaddlePoints", - products: [ - .library( - name: "SaddlePoints", - targets: ["SaddlePoints"]), - ], - dependencies: [], - targets: [ - .target( - name: "SaddlePoints", - dependencies: []), - .testTarget( - name: "SaddlePointsTests", - dependencies: ["SaddlePoints"]), - ] + name: "SaddlePoints", + products: [ + .library( + name: "SaddlePoints", + targets: ["SaddlePoints"]) + ], + dependencies: [], + targets: [ + .target( + name: "SaddlePoints", + dependencies: []), + .testTarget( + name: "SaddlePointsTests", + dependencies: ["SaddlePoints"]), + ] ) From e2306acf9cfd40af12de99da338c4e01a8c7ea87 Mon Sep 17 00:00:00 2001 From: meatball Date: Thu, 2 Jan 2025 19:41:59 +0100 Subject: [PATCH 3/5] Re generate test file --- .../Tests/ComplexNumbersTests/ComplexNumbersTests.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/exercises/practice/complex-numbers/Tests/ComplexNumbersTests/ComplexNumbersTests.swift b/exercises/practice/complex-numbers/Tests/ComplexNumbersTests/ComplexNumbersTests.swift index 14c2ccab7..e4d4ce1b8 100644 --- a/exercises/practice/complex-numbers/Tests/ComplexNumbersTests/ComplexNumbersTests.swift +++ b/exercises/practice/complex-numbers/Tests/ComplexNumbersTests/ComplexNumbersTests.swift @@ -3,7 +3,7 @@ import Testing @testable import ComplexNumbers -let RUNALL = Bool(ProcessInfo.processInfo.environment["RUNALL", default: "true"]) ?? false +let RUNALL = Bool(ProcessInfo.processInfo.environment["RUNALL", default: "false"]) ?? false @Suite struct ComplexNumbersTests { From 31c31b77fed153038d8d94f05f6a2cf1b696e277 Mon Sep 17 00:00:00 2001 From: meatball Date: Thu, 2 Jan 2025 20:16:23 +0100 Subject: [PATCH 4/5] Fix template of poker --- exercises/practice/poker/.meta/template.swift | 2 +- exercises/practice/poker/Tests/PokerTests/PokerTests.swift | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/exercises/practice/poker/.meta/template.swift b/exercises/practice/poker/.meta/template.swift index 1fb437436..dd8c14376 100644 --- a/exercises/practice/poker/.meta/template.swift +++ b/exercises/practice/poker/.meta/template.swift @@ -12,7 +12,7 @@ let RUNALL = Bool(ProcessInfo.processInfo.environment["RUNALL", default: "false" @Test("{{case.description}}", .enabled(if: RUNALL)) {% endif -%} func test{{case.description |camelCase }}() { - let poker = {{exercise|camelCase}}({{case.input.hands}}) + let poker = {{exercise|camelCase}}({{case.input.hands | toStringArray }}) let bestHand = poker.{{case.property}}() let expected = "{{case.expected[0]}}" #expect(bestHand == expected) diff --git a/exercises/practice/poker/Tests/PokerTests/PokerTests.swift b/exercises/practice/poker/Tests/PokerTests/PokerTests.swift index fc4ff37db..3e287bcb5 100644 --- a/exercises/practice/poker/Tests/PokerTests/PokerTests.swift +++ b/exercises/practice/poker/Tests/PokerTests/PokerTests.swift @@ -3,7 +3,7 @@ import Testing @testable import Poker -let RUNALL = Bool(ProcessInfo.processInfo.environment["RUNALL", default: "true"]) ?? false +let RUNALL = Bool(ProcessInfo.processInfo.environment["RUNALL", default: "false"]) ?? false @Suite struct PokerTests { From 9924cb8a2d5739ca5422cde1b09e4ac511813aa0 Mon Sep 17 00:00:00 2001 From: meatball Date: Thu, 2 Jan 2025 20:20:50 +0100 Subject: [PATCH 5/5] Re generate saddle points test --- .../Tests/SaddlePointsTests/SaddlePointsTests.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/exercises/practice/saddle-points/Tests/SaddlePointsTests/SaddlePointsTests.swift b/exercises/practice/saddle-points/Tests/SaddlePointsTests/SaddlePointsTests.swift index 99f332e57..a09a65ac1 100644 --- a/exercises/practice/saddle-points/Tests/SaddlePointsTests/SaddlePointsTests.swift +++ b/exercises/practice/saddle-points/Tests/SaddlePointsTests/SaddlePointsTests.swift @@ -3,7 +3,7 @@ import Testing @testable import SaddlePoints -let RUNALL = Bool(ProcessInfo.processInfo.environment["RUNALL", default: "true"]) ?? false +let RUNALL = Bool(ProcessInfo.processInfo.environment["RUNALL", default: "false"]) ?? false @Suite struct SaddlePointsTests {