diff --git a/config.json b/config.json index c27dcdb3e..d125d2d04 100644 --- a/config.json +++ b/config.json @@ -25,17 +25,14 @@ ,"triangle" ,"scrabble-score" ,"roman-numerals" - ,"binary" ,"prime-factors" ,"raindrops" ,"bob" ,"strain" ,"atbash-cipher" ,"crypto-square" - ,"trinary" ,"rna-transcription" ,"sieve" - ,"octal" ,"luhn" ,"series" ,"pig-latin" @@ -57,7 +54,6 @@ ,"queen-attack" ,"binary-search" ,"binary-search-tree" - ,"hexadecimal" ,"largest-series-product" ,"matrix" ,"house" @@ -69,9 +65,13 @@ ,"saddle-points" ,"poker" ,"dominoes" + ,"all-your-base" ], "deprecated": [ - + "binary" + ,"trinary" + ,"octal" + ,"hexadecimal" ], "ignored": [ "docs", diff --git a/exercises/all-your-base/AllYourBaseExample.swift b/exercises/all-your-base/AllYourBaseExample.swift new file mode 100644 index 000000000..a193017b0 --- /dev/null +++ b/exercises/all-your-base/AllYourBaseExample.swift @@ -0,0 +1,59 @@ +enum BaseError: ErrorProtocol { + case invalidInputBase + case invalidOutputBase + case negativeDigit + case invalidPositiveDigit +} + +struct Base { + + static func outputDigits(inputBase: Int, inputDigits: [Int], outputBase: Int) throws -> [Int] { + guard inputBase >= 2 else { + throw BaseError.invalidInputBase + } + + guard outputBase >= 2 else { + throw BaseError.invalidOutputBase + } + + let sum = try getSum(digits: inputDigits, base: inputBase) + let result = getDigits(sum: sum, base: outputBase) + + return result + } + + private static func getSum(digits: [Int], base: Int) throws -> Int { + var multiplier = 1 + var sum = 0 + + for digit in digits.reversed() { + guard digit >= 0 else { + throw BaseError.negativeDigit + } + guard digit < base else { + throw BaseError.invalidPositiveDigit + } + + sum += digit * multiplier + multiplier *= base + } + + return sum + } + + private static func getDigits(sum: Int, base: Int) -> [Int] { + var sum = sum + var digits = [Int]() + var multiplier = 1 + + while sum > 0 { + multiplier *= base + let value = sum % multiplier + let digit = value / (multiplier / base) + digits.append(digit) + sum -= value + } + + return digits.reversed() + } +} diff --git a/exercises/all-your-base/AllYourBaseTest.swift b/exercises/all-your-base/AllYourBaseTest.swift new file mode 100644 index 000000000..5f54e200f --- /dev/null +++ b/exercises/all-your-base/AllYourBaseTest.swift @@ -0,0 +1,103 @@ +#if swift(>=3.0) + import XCTest +#endif + +class AllYourBaseTest: XCTestCase { + + func errorThrown(byExpression expression: @autoclosure () throws -> T) -> U? { + do { + let _ = try expression() + return nil + } catch { + return error as? U + } + } + + func testSingleBitOneToDecimal() { + XCTAssertEqual(try! Base.outputDigits(inputBase: 2, inputDigits: [1], outputBase: 10), [1]) + } + + func testBinaryToSingleDecimal() { + XCTAssertEqual(try! Base.outputDigits(inputBase: 2, inputDigits: [1, 0, 1], outputBase: 10), [5]) + } + + func testSingleDecimalToBinary() { + XCTAssertEqual(try! Base.outputDigits(inputBase: 10, inputDigits: [5], outputBase: 2), [1, 0, 1]) + } + + func testBinaryToMultipleDecimal() { + XCTAssertEqual(try! Base.outputDigits(inputBase: 2, inputDigits: [1, 0, 1, 0, 1, 0], outputBase: 10), [4, 2]) + } + + func testDecimalToBinary() { + XCTAssertEqual(try! Base.outputDigits(inputBase: 10, inputDigits: [4, 2], outputBase: 2), [1, 0, 1, 0, 1, 0]) + } + + func testTrinaryToHexadecimal() { + XCTAssertEqual(try! Base.outputDigits(inputBase: 3, inputDigits: [1, 1, 2, 0], outputBase: 16), [2, 10]) + } + + func testHexadecimalToTrinary() { + XCTAssertEqual(try! Base.outputDigits(inputBase: 16, inputDigits: [2, 10], outputBase: 3), [1, 1, 2, 0]) + } + + func test15BitInteger() { + XCTAssertEqual(try! Base.outputDigits(inputBase: 97, inputDigits: [3, 46, 60], outputBase: 73), [6, 10, 45]) + } + + func testEmptyList() { + XCTAssertEqual(try! Base.outputDigits(inputBase: 2, inputDigits: [], outputBase: 10), []) + } + + func testSingleZero() { + XCTAssertEqual(try! Base.outputDigits(inputBase: 10, inputDigits: [0], outputBase: 2), []) + } + + func testMultipleZeros() { + XCTAssertEqual(try! Base.outputDigits(inputBase: 10, inputDigits: [0, 0, 0], outputBase: 2), []) + } + + func testLeadingZeros() { + XCTAssertEqual(try! Base.outputDigits(inputBase: 7, inputDigits: [0, 6, 0], outputBase: 10), [4, 2]) + } + + func testNegativeDigit() { + let error: BaseError? = errorThrown(byExpression: try Base.outputDigits(inputBase: 2, inputDigits: [1, -1, 1, 0, 1, 0], outputBase: 10)) + XCTAssertTrue(error == .negativeDigit) + } + + func testInvalidPositiveDigit() { + let error: BaseError? = errorThrown(byExpression: try Base.outputDigits(inputBase: 2, inputDigits: [1, 2, 1, 0, 1, 0], outputBase: 10)) + XCTAssertTrue(error == .invalidPositiveDigit) + } + + func testFirstBaseIsOne() { + let error: BaseError? = errorThrown(byExpression: try Base.outputDigits(inputBase: 1, inputDigits: [], outputBase: 10)) + XCTAssertTrue(error == .invalidInputBase) + } + + func testSecondBaseIsOne() { + let error: BaseError? = errorThrown(byExpression: try Base.outputDigits(inputBase: 2, inputDigits: [1, 0, 1, 0, 1, 0], outputBase: 1)) + XCTAssertTrue(error == .invalidOutputBase) + } + + func testFirstBaseIsZero() { + let error: BaseError? = errorThrown(byExpression: try Base.outputDigits(inputBase: 0, inputDigits: [], outputBase: 10)) + XCTAssertTrue(error == .invalidInputBase) + } + + func testSecondBaseIsZero() { + let error: BaseError? = errorThrown(byExpression: try Base.outputDigits(inputBase: 10, inputDigits: [7], outputBase: 0)) + XCTAssertTrue(error == .invalidOutputBase) + } + + func testFirstBaseIsNegative() { + let error: BaseError? = errorThrown(byExpression: try Base.outputDigits(inputBase: -2, inputDigits: [1], outputBase: 10)) + XCTAssertTrue(error == .invalidInputBase) + } + + func testSecondBaseIsNegative() { + let error: BaseError? = errorThrown(byExpression: try Base.outputDigits(inputBase: 2, inputDigits: [1], outputBase: -7)) + XCTAssertTrue(error == .invalidOutputBase) + } +} diff --git a/xcodeProject/xSwift.xcodeproj/project.pbxproj b/xcodeProject/xSwift.xcodeproj/project.pbxproj index a128dd7a1..caa4a7d3f 100755 --- a/xcodeProject/xSwift.xcodeproj/project.pbxproj +++ b/xcodeProject/xSwift.xcodeproj/project.pbxproj @@ -125,6 +125,8 @@ E90D62001C642EFB00C266D3 /* OcrNumbersTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = E90D61FF1C642EFB00C266D3 /* OcrNumbersTest.swift */; }; E90D62061C653AC000C266D3 /* PalindromeProductsExample.swift in Sources */ = {isa = PBXBuildFile; fileRef = E90D62051C653AC000C266D3 /* PalindromeProductsExample.swift */; }; E90D62081C653ADC00C266D3 /* PalindromeProductsTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = E90D62071C653ADC00C266D3 /* PalindromeProductsTest.swift */; }; + E90DE39C1D3E812300F3B881 /* AllYourBaseExample.swift in Sources */ = {isa = PBXBuildFile; fileRef = E90DE39B1D3E812300F3B881 /* AllYourBaseExample.swift */; }; + E90DE39E1D3E818000F3B881 /* AllYourBaseTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = E90DE39D1D3E818000F3B881 /* AllYourBaseTest.swift */; }; E94BDECF1C510E68009318BB /* BinarySearchExample.swift in Sources */ = {isa = PBXBuildFile; fileRef = E94BDECD1C510E68009318BB /* BinarySearchExample.swift */; }; E94BDED01C510E68009318BB /* BinarySearchTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = E94BDECE1C510E68009318BB /* BinarySearchTest.swift */; }; E9AFA1481C593AF5006AD72D /* BinarySearchTreeExample.swift in Sources */ = {isa = PBXBuildFile; fileRef = E9AFA1461C593AF5006AD72D /* BinarySearchTreeExample.swift */; }; @@ -273,6 +275,8 @@ E90D61FF1C642EFB00C266D3 /* OcrNumbersTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; name = OcrNumbersTest.swift; path = "ocr-numbers/OcrNumbersTest.swift"; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.swift; }; E90D62051C653AC000C266D3 /* PalindromeProductsExample.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = PalindromeProductsExample.swift; path = "palindrome-products/PalindromeProductsExample.swift"; sourceTree = ""; }; E90D62071C653ADC00C266D3 /* PalindromeProductsTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; name = PalindromeProductsTest.swift; path = "palindrome-products/PalindromeProductsTest.swift"; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.swift; }; + E90DE39B1D3E812300F3B881 /* AllYourBaseExample.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = AllYourBaseExample.swift; path = "../all-your-base/AllYourBaseExample.swift"; sourceTree = ""; }; + E90DE39D1D3E818000F3B881 /* AllYourBaseTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = AllYourBaseTest.swift; path = "../all-your-base/AllYourBaseTest.swift"; sourceTree = ""; }; E94BDECD1C510E68009318BB /* BinarySearchExample.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = BinarySearchExample.swift; path = "binary-search/BinarySearchExample.swift"; sourceTree = ""; }; E94BDECE1C510E68009318BB /* BinarySearchTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; name = BinarySearchTest.swift; path = "binary-search/BinarySearchTest.swift"; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.swift; }; E9AFA1461C593AF5006AD72D /* BinarySearchTreeExample.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; name = BinarySearchTreeExample.swift; path = "binary-search-tree/BinarySearchTreeExample.swift"; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.swift; }; @@ -314,6 +318,7 @@ children = ( 1E9A62E91C506EFC00E28AE1 /* accumulate */, 1E9A62EC1C506EFC00E28AE1 /* acronym */, + E90DE3991D3E80F700F3B881 /* all-your-base */, 1E9A62EF1C506EFC00E28AE1 /* allergies */, 1E9A62F21C506EFC00E28AE1 /* anagram */, 1E9A62F51C506EFC00E28AE1 /* atbash-cipher */, @@ -948,6 +953,16 @@ name = "palindrome-products"; sourceTree = ""; }; + E90DE3991D3E80F700F3B881 /* all-your-base */ = { + isa = PBXGroup; + children = ( + E90DE39B1D3E812300F3B881 /* AllYourBaseExample.swift */, + E90DE39D1D3E818000F3B881 /* AllYourBaseTest.swift */, + ); + name = "all-your-base"; + path = acronym; + sourceTree = ""; + }; E94BDECB1C510DF4009318BB /* binary-search */ = { isa = PBXGroup; children = ( @@ -1178,12 +1193,14 @@ 1E167A111C8AA5D7001EAD90 /* PokerExample.swift in Sources */, 1E9A639E1C506EFD00E28AE1 /* EtlExample.swift in Sources */, 1EAF95E11C90C587009DDCB6 /* DominoesTest.swift in Sources */, + E90DE39C1D3E812300F3B881 /* AllYourBaseExample.swift in Sources */, 1E9A63CE1C506EFD00E28AE1 /* RobotSimulatorExample.swift in Sources */, 1E9A639D1C506EFD00E28AE1 /* DifferenceOfSquaresTest.swift in Sources */, E9AFA1531C5945C9006AD72D /* HexadecimalTest.swift in Sources */, 1E9A63AF1C506EFD00E28AE1 /* LeapTest.swift in Sources */, 1E9A63901C506EFD00E28AE1 /* AtbashExample.swift in Sources */, 1E9A63C61C506EFD00E28AE1 /* QueenAttackExample.swift in Sources */, + E90DE39E1D3E818000F3B881 /* AllYourBaseTest.swift in Sources */, E908CD481C6AD076005D081E /* FoodChainTest.swift in Sources */, 1E9A63D91C506EFD00E28AE1 /* SieveTest.swift in Sources */, 1E9A63AA1C506EFD00E28AE1 /* helloWorldTest.swift in Sources */,