From 43d8ff97bf66b8f3b4ea044d53f3ee9efd16e930 Mon Sep 17 00:00:00 2001 From: meatball Date: Thu, 26 Dec 2024 23:04:23 +0100 Subject: [PATCH 1/8] 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/8] 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/8] 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/8] 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/8] 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 { From bda390a808e012f67580ea2d8dade7d145015104 Mon Sep 17 00:00:00 2001 From: meatball Date: Sun, 30 Mar 2025 23:40:48 +0200 Subject: [PATCH 6/8] Bump numerics version --- exercises/practice/complex-numbers/Package.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/exercises/practice/complex-numbers/Package.swift b/exercises/practice/complex-numbers/Package.swift index 50c3ce2c6..4b59bef1a 100644 --- a/exercises/practice/complex-numbers/Package.swift +++ b/exercises/practice/complex-numbers/Package.swift @@ -10,7 +10,7 @@ let package = Package( targets: ["ComplexNumbers"]) ], dependencies: [ - .package(url: "https://github.com/apple/swift-numerics", from: "1.0.2") + .package(url: "https://github.com/apple/swift-numerics", from: "1.0.3") ], targets: [ .target( From 8a9724db488f03b86113dabe132d20081bc75cd7 Mon Sep 17 00:00:00 2001 From: meatball <69751659+meatball133@users.noreply.github.com> Date: Sat, 19 Apr 2025 22:28:28 +0200 Subject: [PATCH 7/8] Update instructions.append.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: András B Nagy <20251272+BNAndras@users.noreply.github.com> --- exercises/practice/complex-numbers/.docs/instructions.append.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/exercises/practice/complex-numbers/.docs/instructions.append.md b/exercises/practice/complex-numbers/.docs/instructions.append.md index 91e07b0d0..c50957db2 100644 --- a/exercises/practice/complex-numbers/.docs/instructions.append.md +++ b/exercises/practice/complex-numbers/.docs/instructions.append.md @@ -3,7 +3,7 @@ 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. +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. From c841958df32b7bdb02981bb088dcdc8a387d3ca9 Mon Sep 17 00:00:00 2001 From: meatball <69751659+meatball133@users.noreply.github.com> Date: Sat, 19 Apr 2025 22:28:35 +0200 Subject: [PATCH 8/8] Update instructions.append.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: András B Nagy <20251272+BNAndras@users.noreply.github.com> --- exercises/practice/complex-numbers/.docs/instructions.append.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/exercises/practice/complex-numbers/.docs/instructions.append.md b/exercises/practice/complex-numbers/.docs/instructions.append.md index c50957db2..688ff34d7 100644 --- a/exercises/practice/complex-numbers/.docs/instructions.append.md +++ b/exercises/practice/complex-numbers/.docs/instructions.append.md @@ -6,6 +6,6 @@ It might be useful to use the method `isApproximatelyEqual(to:absoluteTolerance: 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. +You are also free to implement your own method to compare the two complex numbers. [swift-numberics]: https://github.com/apple/swift-numerics