diff --git a/config.json b/config.json index 0656f4ae..9ec84983 100644 --- a/config.json +++ b/config.json @@ -787,6 +787,14 @@ "prerequisites": [], "difficulty": 3 }, + { + "slug": "resistor-color-trio", + "name": "Resistor Color Trio", + "uuid": "bfd64381-b035-46e5-827b-99ed8b674cde", + "practices": [], + "prerequisites": [], + "difficulty": 3 + }, { "slug": "acronym", "name": "Acronym", diff --git a/exercises/practice/resistor-color-trio/.docs/instructions.md b/exercises/practice/resistor-color-trio/.docs/instructions.md new file mode 100644 index 00000000..1ac5cf5e --- /dev/null +++ b/exercises/practice/resistor-color-trio/.docs/instructions.md @@ -0,0 +1,56 @@ +# Instructions + +If you want to build something using a Raspberry Pi, you'll probably use _resistors_. +For this exercise, you need to know only three things about them: + +- Each resistor has a resistance value. +- Resistors are small - so small in fact that if you printed the resistance value on them, it would be hard to read. + To get around this problem, manufacturers print color-coded bands onto the resistors to denote their resistance values. +- Each band acts as a digit of a number. + For example, if they printed a brown band (value 1) followed by a green band (value 5), it would translate to the number 15. + In this exercise, you are going to create a helpful program so that you don't have to remember the values of the bands. + The program will take 3 colors as input, and outputs the correct value, in ohms. + The color bands are encoded as follows: + +- black: 0 +- brown: 1 +- red: 2 +- orange: 3 +- yellow: 4 +- green: 5 +- blue: 6 +- violet: 7 +- grey: 8 +- white: 9 + +In Resistor Color Duo you decoded the first two colors. +For instance: orange-orange got the main value `33`. +The third color stands for how many zeros need to be added to the main value. +The main value plus the zeros gives us a value in ohms. +For the exercise it doesn't matter what ohms really are. +For example: + +- orange-orange-black would be 33 and no zeros, which becomes 33 ohms. +- orange-orange-red would be 33 and 2 zeros, which becomes 3300 ohms. +- orange-orange-orange would be 33 and 3 zeros, which becomes 33000 ohms. + +(If Math is your thing, you may want to think of the zeros as exponents of 10. +If Math is not your thing, go with the zeros. +It really is the same thing, just in plain English instead of Math lingo.) + +This exercise is about translating the colors into a label: + +> "... ohms" + +So an input of `"orange", "orange", "black"` should return: + +> "33 ohms" + +When we get to larger resistors, a [metric prefix][metric-prefix] is used to indicate a larger magnitude of ohms, such as "kiloohms". +That is similar to saying "2 kilometers" instead of "2000 meters", or "2 kilograms" for "2000 grams". + +For example, an input of `"orange", "orange", "orange"` should return: + +> "33 kiloohms" + +[metric-prefix]: https://en.wikipedia.org/wiki/Metric_prefix diff --git a/exercises/practice/resistor-color-trio/.meta/Sources/ResistorColorTrio/ResistorColorTrioExample.swift b/exercises/practice/resistor-color-trio/.meta/Sources/ResistorColorTrio/ResistorColorTrioExample.swift new file mode 100644 index 00000000..7f2208e6 --- /dev/null +++ b/exercises/practice/resistor-color-trio/.meta/Sources/ResistorColorTrio/ResistorColorTrioExample.swift @@ -0,0 +1,86 @@ +import Foundation + +enum Color: String, CaseIterable { + case black + case brown + case red + case orange + case yellow + case green + case blue + case violet + case grey + case white +} + +enum Unit: String { + case ohms + case kiloohms + case megaohms + case gigaohms +} + +enum ResistorColorTrioError: Error { + case invalidInput + case unknownColor +} + +enum ResistorColorTrio { + + static func label(for colors: [String]) throws -> String { + guard colors.count >= 3 else { + throw ResistorColorTrioError.invalidInput + } + + let convertedColors = try colors.reduce(into: [Color]()) { partialResult, string in + guard let color = Color(rawValue: string) else { + throw ResistorColorTrioError.unknownColor + } + partialResult.append(color) + } + + var zeros = 0 + var value = 0 + let firstDigit = code(for: convertedColors[0]) + if (firstDigit > 0) { + value += firstDigit + } + + let secondDigit = code(for: convertedColors[1]) + if (secondDigit == 0) { + zeros += 1 + } + else { + value = value * 10 + secondDigit + } + + zeros += code(for: convertedColors[2]) + let (remaining, unit) = strip(zeros) + return "\(value * Int(pow(10.0, Double(remaining)))) \(unit)" + } + + private static func strip(_ zeros: Int) -> (remaining: Int, unit: String) { + switch zeros { + case 0, 1, 2: return (zeros % 3, Unit.ohms.rawValue) + case 3, 4, 5: return (zeros % 3, Unit.kiloohms.rawValue) + case 6, 7, 8: return (zeros % 3, Unit.megaohms.rawValue) + case 9: return (0, Unit.gigaohms.rawValue) + default: return (0, Unit.ohms.rawValue) + } + } +} + +fileprivate func code(for color: Color) -> Int { + switch color { + case .black: return 0 + case .brown: return 1 + case .red: return 2 + case .orange: return 3 + case .yellow: return 4 + case .green: return 5 + case .blue: return 6 + case .violet: return 7 + case .grey: return 8 + case .white: return 9 + } +} \ No newline at end of file diff --git a/exercises/practice/resistor-color-trio/.meta/config.json b/exercises/practice/resistor-color-trio/.meta/config.json new file mode 100644 index 00000000..3cabc3af --- /dev/null +++ b/exercises/practice/resistor-color-trio/.meta/config.json @@ -0,0 +1,19 @@ +{ + "authors": [ + "Sencudra" + ], + "files": { + "solution": [ + "Sources/ResistorColorTrio/ResistorColorTrio.swift" + ], + "test": [ + "Tests/ResistorColorTrioTests/ResistorColorTrioTests.swift" + ], + "example": [ + ".meta/Sources/ResistorColorTrio/ResistorColorTrioExample.swift" + ] + }, + "blurb": "Convert color codes, as used on resistors, to a human-readable label.", + "source": "Maud de Vries, Erik Schierboom", + "source_url": "https://github.com/exercism/problem-specifications/issues/1549" +} diff --git a/exercises/practice/resistor-color-trio/.meta/template.swift b/exercises/practice/resistor-color-trio/.meta/template.swift new file mode 100644 index 00000000..dd1b05f4 --- /dev/null +++ b/exercises/practice/resistor-color-trio/.meta/template.swift @@ -0,0 +1,18 @@ +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 }}() throws { + #expect(try ResistorColorTrio.{{ case.property }}(for: {{ case.input.colors | toStringArray }}) == "{{ case.expected.value }} {{case.expected.unit}}") + } + {% endfor -%} +} diff --git a/exercises/practice/resistor-color-trio/.meta/tests.toml b/exercises/practice/resistor-color-trio/.meta/tests.toml new file mode 100644 index 00000000..b7d45fa5 --- /dev/null +++ b/exercises/practice/resistor-color-trio/.meta/tests.toml @@ -0,0 +1,40 @@ +# This is an auto-generated file. +# +# Regenerating this file via `configlet sync` will: +# - Recreate every `description` key/value pair +# - Recreate every `reimplements` key/value pair, where they exist in problem-specifications +# - Remove any `include = true` key/value pair (an omitted `include` key implies inclusion) +# - Preserve any other key/value pair +# +# As user-added comments (using the # character) will be removed when this file +# is regenerated, comments can be added via a `comment` key. + +[d6863355-15b7-40bb-abe0-bfb1a25512ed] +description = "Orange and orange and black" + +[1224a3a9-8c8e-4032-843a-5224e04647d6] +description = "Blue and grey and brown" + +[b8bda7dc-6b95-4539-abb2-2ad51d66a207] +description = "Red and black and red" + +[5b1e74bc-d838-4eda-bbb3-eaba988e733b] +description = "Green and brown and orange" + +[f5d37ef9-1919-4719-a90d-a33c5a6934c9] +description = "Yellow and violet and yellow" + +[5f6404a7-5bb3-4283-877d-3d39bcc33854] +description = "Blue and violet and blue" + +[7d3a6ab8-e40e-46c3-98b1-91639fff2344] +description = "Minimum possible value" + +[ca0aa0ac-3825-42de-9f07-dac68cc580fd] +description = "Maximum possible value" + +[0061a76c-903a-4714-8ce2-f26ce23b0e09] +description = "First two colors make an invalid octal number" + +[30872c92-f567-4b69-a105-8455611c10c4] +description = "Ignore extra colors" diff --git a/exercises/practice/resistor-color-trio/Package.swift b/exercises/practice/resistor-color-trio/Package.swift new file mode 100644 index 00000000..fba3f577 --- /dev/null +++ b/exercises/practice/resistor-color-trio/Package.swift @@ -0,0 +1,21 @@ +// swift-tools-version:6.0 + +import PackageDescription + +let package = Package( + name: "ResistorColorTrio", + products: [ + .library( + name: "ResistorColorTrio", + targets: ["ResistorColorTrio"]) + ], + dependencies: [], + targets: [ + .target( + name: "ResistorColorTrio", + dependencies: []), + .testTarget( + name: "ResistorColorTrioTests", + dependencies: ["ResistorColorTrio"]), + ] +) \ No newline at end of file diff --git a/exercises/practice/resistor-color-trio/Sources/ResistorColorTrio/ResistorColorTrio.swift b/exercises/practice/resistor-color-trio/Sources/ResistorColorTrio/ResistorColorTrio.swift new file mode 100644 index 00000000..4371c4f2 --- /dev/null +++ b/exercises/practice/resistor-color-trio/Sources/ResistorColorTrio/ResistorColorTrio.swift @@ -0,0 +1,5 @@ +import Foundation + +enum ResistorColorTrio { + // Write your code for the 'ResistorColorTrio' exercise in this file. +} \ No newline at end of file diff --git a/exercises/practice/resistor-color-trio/Tests/ResistorColorTrioTests/ResistorColorTrioTests.swift b/exercises/practice/resistor-color-trio/Tests/ResistorColorTrioTests/ResistorColorTrioTests.swift new file mode 100644 index 00000000..ea529c8e --- /dev/null +++ b/exercises/practice/resistor-color-trio/Tests/ResistorColorTrioTests/ResistorColorTrioTests.swift @@ -0,0 +1,60 @@ +import Foundation +import Testing + +@testable import ResistorColorTrio + +let RUNALL = Bool(ProcessInfo.processInfo.environment["RUNALL", default: "false"]) ?? false + +@Suite struct ResistorColorTrioTests { + + @Test("Orange and orange and black") + func testOrangeAndOrangeAndBlack() throws { + #expect(try ResistorColorTrio.label(for: ["orange", "orange", "black"]) == "33 ohms") + } + + @Test("Blue and grey and brown", .enabled(if: RUNALL)) + func testBlueAndGreyAndBrown() throws { + #expect(try ResistorColorTrio.label(for: ["blue", "grey", "brown"]) == "680 ohms") + } + + @Test("Red and black and red", .enabled(if: RUNALL)) + func testRedAndBlackAndRed() throws { + #expect(try ResistorColorTrio.label(for: ["red", "black", "red"]) == "2 kiloohms") + } + + @Test("Green and brown and orange", .enabled(if: RUNALL)) + func testGreenAndBrownAndOrange() throws { + #expect(try ResistorColorTrio.label(for: ["green", "brown", "orange"]) == "51 kiloohms") + } + + @Test("Yellow and violet and yellow", .enabled(if: RUNALL)) + func testYellowAndVioletAndYellow() throws { + #expect(try ResistorColorTrio.label(for: ["yellow", "violet", "yellow"]) == "470 kiloohms") + } + + @Test("Blue and violet and blue", .enabled(if: RUNALL)) + func testBlueAndVioletAndBlue() throws { + #expect(try ResistorColorTrio.label(for: ["blue", "violet", "blue"]) == "67 megaohms") + } + + @Test("Minimum possible value", .enabled(if: RUNALL)) + func testMinimumPossibleValue() throws { + #expect(try ResistorColorTrio.label(for: ["black", "black", "black"]) == "0 ohms") + } + + @Test("Maximum possible value", .enabled(if: RUNALL)) + func testMaximumPossibleValue() throws { + #expect(try ResistorColorTrio.label(for: ["white", "white", "white"]) == "99 gigaohms") + } + + @Test("First two colors make an invalid octal number", .enabled(if: RUNALL)) + func testFirstTwoColorsMakeAnInvalidOctalNumber() throws { + #expect(try ResistorColorTrio.label(for: ["black", "grey", "black"]) == "8 ohms") + } + + @Test("Ignore extra colors", .enabled(if: RUNALL)) + func testIgnoreExtraColors() throws { + #expect( + try ResistorColorTrio.label(for: ["blue", "green", "yellow", "orange"]) == "650 kiloohms") + } +}