exercism / swift

Exercism exercises in Swift.
https://exercism.org/tracks/swift
MIT License
113 stars 158 forks source link

Building a training set of tags for swift #703

Closed ErikSchierboom closed 11 months ago

ErikSchierboom commented 11 months ago

Hello lovely maintainers :wave:

We've recently added "tags" to student's solutions. These express the constructs, paradigms and techniques that a solution uses. We are going to be using these tags for lots of things including filtering, pointing a student to alternative approaches, and much more.

In order to do this, we've built out a full AST-based tagger in C#, which has allowed us to do things like detect recursion or bit shifting. We've set things up so other tracks can do the same for their languages, but its a lot of work, and we've determined that actually it may be unnecessary. Instead we think that we can use machine learning to achieve tagging with good enough results. We've fine-tuned a model that can determine the correct tags for C# from the examples with a high success rate. It's also doing reasonably well in an untrained state for other languages. We think that with only a few examples per language, we can potentially get some quite good results, and that we can then refine things further as we go.

I released a new video on the Insiders page that talks through this in more detail.

We're going to be adding a fully-fledged UI in the coming weeks that allow maintainers and mentors to tag solutions and create training sets for the neural networks, but to start with, we're hoping you would be willing to manually tag 20 solutions for this track. In this post we'll add 20 comments, each with a student's solution, and the tags our model has generated. Your mission (should you choose to accept it) is to edit the tags on each issue, removing any incorrect ones, and add any that are missing. In order to build one model that performs well across languages, it's best if you stick as closely as possible to the C# tags as you can. Those are listed here. If you want to add extra tags, that's totally fine, but please don't arbitrarily reword existing tags, even if you don't like what Erik's chosen, as it'll just make it less likely that your language gets the correct tags assigned by the neural network.


To summarise - there are two paths forward for this issue:

  1. You're up for helping: Add a comment saying you're up for helping. Update the tags some time in the next few days. Add a comment when you're done. We'll then add them to our training set and move forward.
  2. You not up for helping: No problem! Just please add a comment letting us know :)

If you tell us you're not able/wanting to help or there's no comment added, we'll automatically crowd-source this in a week or so.

Finally, if you have questions or want to discuss things, it would be best done on the forum, so the knowledge can be shared across all maintainers in all tracks.

Thanks for your help! :blue_heart:


Note: Meta discussion on the forum

ErikSchierboom commented 11 months ago

Exercise: two-fer

Code

import XCTest
@testable import TwoFer

class TwoFerTests: XCTestCase {

    func testNoNameGiven() {
        XCTAssertEqual(TwoFer.twoFer(), "One for you, one for me.")
    }

    func testANameGiven() {
        XCTAssertEqual(TwoFer.twoFer(name: "Alice"), "One for Alice, one for me.")
    }

    func testAnotherNameGiven() {
        XCTAssertEqual(TwoFer.twoFer(name: "Bob"), "One for Bob, one for me.")
    }

    static var allTests: [(String, (TwoFerTests) -> () throws -> Void)] {
        return [
            ("testNoNameGiven", testNoNameGiven),
            ("testANameGiven", testANameGiven),
            ("testAnotherNameGiven", testAnotherNameGiven),
        ]
    }
}

Tags:

construct:class
construct:func
construct:import
construct:method
construct:parameter
construct:return
construct:static-member
construct:tuple
construct:varargs
construct:variable
construct:visibility-modifiers
paradigm:object-oriented
ErikSchierboom commented 11 months ago

Exercise: leap

Code

struct Year {
  let year: Int

  init(calendarYear: Int) {
    self.year = calendarYear
  }

  var isLeapYear : Bool {
    get {
      return divisibleBy(dividend: year, divisor: 4) &&
            !divisibleBy(dividend: year, divisor: 100) ||
             divisibleBy(dividend: year, divisor: 400)
    }
  }

  internal func divisibleBy(dividend: Int, divisor: Int) -> Bool {
    return dividend % divisor == 0
  }
}

Tags:

construct:assignment
construct:boolean
construct:computed-property
construct:getter
construct:initializer
construct:int
construct:integral-number
construct:invocation
construct:logical-and
construct:logical-or
construct:method
construct:number
construct:parameter
construct:property
construct:return
construct:struct
construct:variable
construct:visibility-modifiers
paradigm:imperative
paradigm:object-oriented
technique:boolean-logic
ErikSchierboom commented 11 months ago

Exercise: difference-of-squares

Code

import Foundation

struct Squares {
    let numList: [Int]

    init(_ naturalNumber: Int) {
        numList = Array((1...naturalNumber))
    }

    var squareOfSums: Int {
        let sum = numList.reduce(0, +)
        return sum * sum
    }

    var sumOfSquares: Int {
        let squares = numList.map { $0 * $0 }
        return squares.reduce(0, +)
    }

    var differenceOfSquares: Int {
        return squareOfSums - sumOfSquares
    }
}

Tags:

construct:array
construct:assignment
construct:closure
construct:expression
construct:import
construct:init
construct:int
construct:integral-number
construct:invocation
construct:let
construct:method
construct:multiply
construct:number
construct:parameter
construct:property
construct:return
construct:struct
construct:subtract
construct:variable
construct:visibility-modifiers
paradigm:functional
paradigm:imperative
paradigm:object-oriented
technique:higher-order-functions
ErikSchierboom commented 11 months ago

Exercise: rna-transcription

Code

// This implementation is super verbose and could be more succintly
// implemented via a dictionary of characters, but I am currently
// addicted to enums.
//
// This is not a good excuse.

public enum TranscriptionError: Error {
  case invalidCharacter(_: Character)
}

private enum DNA {
  case Adenine
  case Cytosine
  case Guanine
  case Thymine

  static func fromCharacter(_ ch: Character) throws -> DNA {
    switch ch {
      case "A": return .Adenine
      case "C": return .Cytosine
      case "G": return .Guanine
      case "T": return .Thymine
      default: throw TranscriptionError.invalidCharacter(ch)
    }
  }

  var transcribed: RNA {
    switch self {
      // I know I don't need to repeat 'DNA' and 'RNA' here, as they can
      // be inferred by the compiler, but I think mentioning them explicitly
      // improves readability, so I'm leaving them in.
      case DNA.Guanine: return RNA.Cytosine
      case DNA.Cytosine: return RNA.Guanine
      case DNA.Thymine: return RNA.Adenine
      case DNA.Adenine: return RNA.Uracil
    }
  }
}

private enum RNA {
  case Adenine
  case Cytosine
  case Guanine
  case Uracil

  var character: Character {
    switch self {
      case .Adenine: return "A"
      case .Cytosine: return "C"
      case .Guanine: return "G"
      case .Uracil: return "U"
    }
  }
}

public struct Nucleotide {
  private let strand: [DNA]

  init(_ strand: String) throws {
    self.strand = try strand.map({ try DNA.fromCharacter($0) })
  }

  func complementOfDNA() -> String {
    return String(strand.map({ $0.transcribed }).map({ $0.character }))
  }
}

Tags:

construct:assignment
construct:case
construct:char
construct:class
construct:comment
construct:computed-property
construct:enum
construct:initializer
construct:invocation
construct:lambda
construct:let
construct:method
construct:nested-type
construct:parameter
construct:pattern-matching
construct:return
construct:string
construct:struct
construct:switch
construct:throw
construct:throws
construct:tuple
construct:variable
construct:visibility-modifiers
paradigm:functional
paradigm:imperative
paradigm:object-oriented
technique:exceptions
technique:higher-order-functions
ErikSchierboom commented 11 months ago

Exercise: sum-of-multiples

Code

struct SumOfMultiples {
    static func toLimit(n: Int, inMultiples: [Int]) -> Int {
        var res = [Int]()
        for i in 1..<n {
            inMultiples.forEach {
                $0 > 0 && (i % $0 == 0  && !res.contains(i)) ?
                res.append(i) : ()
            }
        }
        return res.isEmpty ? 0 : res.reduce(0, combine: +)
    }
}

Tags:

construct:add
construct:boolean
construct:braces
construct:closure
construct:for-loop
construct:function
construct:implicit-conversion
construct:int
construct:integral-number
construct:invocation
construct:logical-and
construct:method
construct:number
construct:parameter
construct:return
construct:struct
construct:ternary
construct:trailing-closure
construct:tuple
construct:variable
construct:visibility-modifiers
paradigm:functional
paradigm:imperative
paradigm:object-oriented
technique:boolean-logic
technique:higher-order-functions
technique:looping
ErikSchierboom commented 11 months ago

Exercise: bob

Code

import Foundation

struct Bob {
    enum Responses: String {
        case Silence = "Fine, be that way."
        case Yelling = "Woah, chill out!"
        case Questioning = "Sure."
        case Default = "Whatever."
    }

    private let greeting: String

    var response: Responses {
        if isSilent {
            return .Silence
        } else if isYelling {
            return .Yelling
        } else if isQuestioning {
            return .Questioning
        } else {
            return .Default
        }
    }

    private var isSilent: Bool {
        return greeting.stringByTrimmingCharactersInSet(.whitespaceCharacterSet()).isEmpty
    }

    private var isYelling: Bool {
        return hasAnyUppercaseLetters && isAllUppercase
    }

    private var hasAnyUppercaseLetters: Bool {
        let range = greeting.rangeOfCharacterFromSet(.uppercaseLetterCharacterSet())
        return range != nil
    }

    private var isAllUppercase: Bool {
        return greeting == greeting.uppercaseString
    }

    private var isQuestioning: Bool {
        return greeting.hasSuffix("?")
    }

    init(_ greeting: String) {
        self.greeting = greeting
    }

    static func hey(greeting: String) -> String {
        return Bob(greeting).response.rawValue
    }
}

Tags:

construct:assignment
construct:boolean
construct:enum
construct:if
construct:import
construct:initializer
construct:invocation
construct:logical-and
construct:method
construct:parameter
construct:property
construct:return
construct:string
construct:struct
construct:variable
construct:visibility-modifiers
paradigm:imperative
paradigm:object-oriented
technique:boolean-logic
ErikSchierboom commented 11 months ago

Exercise: bob

Code

import Foundation

class Bob {
    class func hey(phrase: String) -> String {
        if phrase.isBeingSilent {
            return "Fine, be that way."
        } else if phrase.isYelling {
            return "Woah, chill out!"
        } else if phrase.isAsking {
            return "Sure."
        } else {
            return "Whatever."
        }
    }
}

extension String {
    var isBeingSilent: Bool {
        let spaces = NSCharacterSet.whitespaceCharacterSet()
        return self.stringByTrimmingCharactersInSet(spaces).isEmpty
    }

    var alphanumeric: Bool {
        var alpha = false
        for scalar in self.unicodeScalars {
            alpha |= (scalar.value >= 65 && scalar.value <= 90) ||
                (scalar.value >= 97 && scalar.value <= 122)
        }
        return alpha
    }

    var isYelling: Bool {
        return self.alphanumeric && self == self.uppercaseString
    }

    var isAsking: Bool {
        return self.hasSuffix("?")
    }
}

Tags:

construct:assignment
construct:boolean
construct:class
construct:extension
construct:for-loop
construct:if
construct:import
construct:initializer
construct:int
construct:integral-number
construct:logical-and
construct:logical-or
construct:method
construct:number
construct:parameter
construct:return
construct:string
construct:variable
construct:visibility-modifiers
paradigm:imperative
paradigm:object-oriented
technique:boolean-logic
technique:looping
ErikSchierboom commented 11 months ago

Exercise: grains

Code

import Foundation

class Grains {
  enum GrainsError: Error {
    case inputTooLow(String)
    case inputTooHigh(String)
  }

  static func square(_ n: Int) throws -> UInt64 {
    guard n >= 1  else { throw GrainsError.inputTooLow(invalidInputMsg(n)) }
    guard n <= 64 else { throw GrainsError.inputTooHigh(invalidInputMsg(n)) }

    return UInt64(pow(2, Double(n - 1)))
  }

  static var total: UInt64 {
    return try! (1...64).map(square).reduce(0, +)
  }

  static func invalidInputMsg(_ input: Int) -> String {
    return "Input[\(input)] invalid. Input should be between 1 and 64 (inclusive)"
  }
}

Tags:

construct:class
construct:double
construct:enum
construct:floating-point-number
construct:explicit-conversion
construct:extension
construct:floating-point-number
construct:guard
construct:import
construct:int
construct:integral-number
construct:invocation
construct:method
construct:number
construct:parameter
construct:return
construct:string
construct:subtract
construct:throw
construct:throws
construct:try
construct:tuple
construct:varargs
construct:variable
construct:visibility-modifiers
paradigm:object-oriented
technique:exceptions
technique:type-conversion
ErikSchierboom commented 11 months ago

Exercise: accumulate

Code

extension Array {
  func accumulate<NewType>(function: (T) -> NewType) -> Array<NewType>{
    var newArray = Array<NewType>()

    for element in self {
      newArray.append(function(element))
    }
    return newArray
  }
}

Tags:

construct:array
construct:assignment
construct:extension
construct:for-loop
construct:generic-type
construct:invocation
construct:method
construct:parameter
construct:return
construct:variable
construct:visibility-modifiers
paradigm:imperative
paradigm:functional
paradigm:object-oriented
technique:looping
uses:Array
ErikSchierboom commented 11 months ago

Exercise: grade-school

Code

struct GradeSchool {
  typealias Students = [String]
  typealias Roster = [Int: Students]

  var roster = Roster()

  var sortedRoster: [Int: [String]] {
    var sorted = Roster()
    roster.forEach { sorted[$0.0] = $0.1.sort() }
    return sorted
  }

  mutating func addStudent(name: String, grade: Int) {
    var students = roster[grade] ?? Students()
    students.append(name)
    roster[grade] = students
  }

  func studentsInGrade(grade: Int) -> [String] {
    return roster[grade] ?? Students()
  }
}

Tags:

construct:assignment
construct:class
construct:computed-property
construct:constructor
construct:dictionary
construct:func
construct:implicit-conversion
construct:index-lookup
construct:invocation
construct:method
construct:nested-type
construct:parameter
construct:return
construct:string
construct:struct
construct:throw
construct:throw-expression
construct:tuple
construct:typealias
construct:variable
construct:visibility-modifiers
paradigm:object-oriented
technique:exceptions
ErikSchierboom commented 11 months ago

Exercise: diamond

Code

//Solution goes in Sources

enum Diamond {

    static let letters = ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"]

    static func makeDiamond(letter: String) -> [String] {
        let givenLetterIndex = letters.index(of: letter)!
        let lines = givenLetterIndex * 2 + 1
        return (0..<lines).map { (letterIndex) -> String in
            let currentLetterIndex = calculateCurrentLetterIndex(givenLetterIndex: givenLetterIndex,
                                                                 letterIndex: letterIndex)
            let numOuterSpaces = calculateNumberOfOuterSpaces(totalLines: lines,
                                                              currentLetterIndex: currentLetterIndex)

            let currentLetter = letters[currentLetterIndex]
            let firstHalf = spaces(count: numOuterSpaces) + currentLetter + spaces(count: givenLetterIndex - numOuterSpaces)
            return firstHalf + firstHalf.reversed().dropFirst()
        }
    }

    private static func calculateCurrentLetterIndex(givenLetterIndex: Int, letterIndex: Int) -> Int {
        return min(letterIndex, givenLetterIndex - (letterIndex - givenLetterIndex))
    }

    private static func calculateNumberOfOuterSpaces(totalLines: Int, currentLetterIndex: Int) -> Int {
        return (totalLines - (currentLetterIndex * 2)) / 2
    }

    private static func spaces(count: Int) -> String {
        return String(repeating: " ", count: count)
    }
}

Tags:

construct:add
construct:class
construct:comment
construct:divide
construct:enum
construct:implicit-conversion
construct:index-into-array
construct:initializer
construct:int
construct:integral-number
construct:invocation
construct:lambda
construct:let
construct:method
construct:multiply
construct:named-argument
construct:number
construct:parameter
construct:return
construct:string
construct:subtract
construct:throw
construct:tuple
construct:underscore
construct:variable
construct:visibility-modifiers
paradigm:functional
paradigm:object-oriented
technique:exceptions
technique:higher-order-functions
ErikSchierboom commented 11 months ago

Exercise: diamond

Code

//Solution goes in Sources

struct Diamond {
    static func makeDiamond(letter: String) -> [String]{
        let size = Character(letter).distance(to: Character("A"))!
        var up = (0...size).reduce(into: []) { acc, c in
            acc.append(makeLine(forLetter: String(Character(Unicode.Scalar(65+c)!)), size: size))
        }
        up.append(contentsOf: up[0..<size].reversed())
        return up
    }

    private static func makeLine(forLetter letter: String, size: Int) -> String {
        var s = Array(repeating: " ", count: 2 * size + 1)
        let dist = Character(letter).distance(to: Character("A"))!

        s[size-dist] = letter
        s[size+dist] = letter
        return s.joined(separator: "")
    }
}

extension Character {
    var unicode: UInt32? {
        return self.unicodeScalars.first?.value
    }

    func distance(to other: Character) -> Int? {
        guard let a = self.unicode else { return nil }
        guard let b = other.unicode else { return nil }
        return Int(a - b)
    }
}

Tags:

construct:add
construct:assignment
construct:char
construct:class
construct:comment
construct:computed-property
construct:constructor
construct:extension
construct:guard
construct:implicit-conversion
construct:index-lookup
construct:int
construct:integral-number
construct:invocation
construct:lambda
construct:let
construct:method
construct:number
construct:optional
construct:parameter
construct:return
construct:struct
construct:subtract
construct:throw
construct:throw-expression
construct:tuple
construct:variable
construct:visibility-modifiers
paradigm:functional
paradigm:imperative
paradigm:object-oriented
technique:exceptions
technique:higher-order-functions
ErikSchierboom commented 11 months ago

Exercise: diamond

Code

struct Diamond {
    static func makeDiamond(letter: Character) -> [String] {
        let alphabet: [Character] = (0..<26).map { Character(UnicodeScalar(Int("A".unicodeScalars.first!.value) + $0)!) }
        let position: Int = alphabet.index(of: letter)!
        var diamond: [[Character]] = Array(repeating: Array(repeating: " ", count: 1+position*2), count: 1+position)
        alphabet.prefix(through: position).enumerated().forEach {
            diamond[$0][position-$0] = $1
            diamond[$0][position+$0] = $1
        }
        diamond += diamond.dropLast().reversed()
        return diamond.map { String($0) }
    }
}

Tags:

construct:add
construct:assignment
construct:char
construct:closure
construct:explicit-conversion
construct:expression
construct:extension-method
construct:implicit-conversion
construct:index-into-array
construct:int
construct:integral-number
construct:invocation
construct:lambda
construct:let
construct:map
construct:method
construct:multiply
construct:number
construct:parameter
construct:return
construct:string
construct:struct
construct:subtract
construct:throw
construct:tuple
construct:underscore
construct:variable
construct:visibility-modifiers
paradigm:functional
paradigm:imperative
paradigm:object-oriented
technique:exceptions
technique:higher-order-functions
technique:looping
ErikSchierboom commented 11 months ago

Exercise: simple-linked-list

Code

//Solution goes in Sources

class Element<T> {
   var value: T?
   var next: Element?

   init(_ value: T? = nil, _ next: Element? = nil) {
      self.value = value
      self.next = next
   }

   func toArray() -> [T] {
      if let value = self.value {
         var array = [value]

         if let next = self.next {
            array.append(contentsOf: next.toArray())
         }

         return array
      } else {
         return []
      }
   }

   func reverseElements() -> Element<T> {
      return Element.fromArray(self.toArray().reversed())
   }

   class func fromArray(_ array: [T]) -> Element<T> {
      var current: Element<T>?
      var next: Element<T>?

      for value in array.reversed() {
         current = Element(value, next)
         next = current
      }

      if let result = current {
         return result
      } else {
         return Element<T>()
      }
   }
}

Tags:

construct:assignment
construct:class
construct:comment
construct:for-loop
construct:generic-type
construct:if
construct:initializer
construct:invocation
construct:method
construct:nested-type
construct:optional
construct:parameter
construct:return
construct:stored-property
construct:tuple
construct:variable
construct:visibility-modifiers
paradigm:imperative
paradigm:object-oriented
technique:looping
ErikSchierboom commented 11 months ago

Exercise: house

Code

class House {
    /*recite sings "The House that Jack Built" rhyme*/
    static func recite(start: Int = 0, stop: Int = 11) -> String {
        return Array(start...stop)
            .map{ verse($0) }
            .joinWithSeparator("\n\n")
    }

    /*lines is the lines in "The House that Jack Built"*/
    private static let lines = [
        " the house that Jack built.",
        " the malt\nthat lay in",
        " the rat\nthat ate",
        " the cat\nthat killed",
        " the dog\nthat worried",
        " the cow with the crumpled horn\nthat tossed",
        " the maiden all forlorn\nthat milked",
        " the man all tattered and torn\nthat kissed",
        " the priest all shaven and shorn\nthat married",
        " the rooster that crowed in the morn\nthat woke",
        " the farmer sowing his corn\nthat kept",
        " the horse and the hound and the horn\nthat belonged to",
    ]

    /*verse recites a single verse from "The House that Jack Built"*/
    private static func verse(n: Int) -> String {
        return "This is" + lines[0...n]
            .reverse()
            .joinWithSeparator("")
    }
}

Tags:

construct:class
construct:comment
construct:initializer
construct:int
construct:interval
construct:invocation
construct:lambda
construct:let
construct:method
construct:number
construct:optional-parameter
construct:parameter
construct:return
construct:string
construct:throw
construct:variable
construct:visibility-modifiers
paradigm:functional
paradigm:object-oriented
technique:exceptions
technique:higher-order-functions
ErikSchierboom commented 11 months ago

Exercise: roman-numerals

Code

//
//  RomanNumerals.swift
//  exercism-test-runner
//
//  Created by Kevin VanderLugt on 3/22/15.
//  Copyright (c) 2015 Alpine Pipeline, LLC. All rights reserved.
//

import Foundation

extension Int {
    var toRoman: String {
        let romanNumerals: [Int: String] = [ 1: "I", 4: "IV", 5: "V", 9: "IX", 10: "X", 40: "XL", 50: "L",  90: "XC", 100: "C", 400: "CD", 500: "D", 900: "CM", 1000: "M" ]
        let sortedRomanNumerals = sorted(romanNumerals) { $0.0 > $1.0 }

        return sortedRomanNumerals.reduce(("", self), combine: { (remainderTuple, valueTuple) -> (String, Int) in
            var (romanString, remainder) = remainderTuple
            let (numeralConstant, romanNumeral) = valueTuple

            let characterCount = remainder / numeralConstant
            if(characterCount > 0) {
                remainder = remainder % numeralConstant
                romanString += String(count: characterCount, repeatedValue: romanNumeral)
            }

            return (romanString, remainder)
        }).0
    }
}

extension String {
    init(count: Int, repeatedValue value: String) {
        let array = Array(count: count, repeatedValue: value)
        self = "".join(array)
    }
}

Tags:

construct:assignment
construct:comment
construct:computed-property
construct:dictionary
construct:divide
construct:extension
construct:if
construct:implicit-conversion
construct:initializer
construct:int
construct:integral-number
construct:invocation
construct:lambda
construct:let
construct:method
construct:number
construct:parameter
construct:return
construct:string
construct:tuple
construct:variable
construct:visibility-modifiers
paradigm:functional
paradigm:imperative
paradigm:object-oriented
technique:higher-order-functions
ErikSchierboom commented 11 months ago

Exercise: simple-cipher

Code

//Solution goes in Sources
import Foundation

struct Cipher {

    let key: String

    private static let a: UnicodeScalar = "a"

    init() {
        self.key = Cipher.generateKey()
    }

    init?(key: String) {
        guard key.rangeOfCharacter(from: .uppercaseLetters) == nil else {
            return nil
        }
        guard key.rangeOfCharacter(from: .decimalDigits) == nil else {
            return nil
        }
        guard key.characters.count > 0 else {
            return nil
        }

        self.key = key
    }

    private static func generateKey() -> String {
        var key = ""

        for _ in 0..<100 {
            let offset = arc4random_uniform(26)
            let unicodePoint = offset + Cipher.a.value
            let unicodeScalar = UnicodeScalar(unicodePoint) ?? "a"
            key.append(Character(unicodeScalar))
        }

        return key
    }

    private func offset(_ unicodeScalar: UnicodeScalar) -> Int {
        return Int(unicodeScalar.value - Cipher.a.value)
    }

    private func character(from offset: Int) -> Character? {
        let unicodePoint = offset + Int(Cipher.a.value)

        guard let unicodeScalar = UnicodeScalar(unicodePoint) else {
            return nil
        }

        return Character(unicodeScalar)
    }

    private func encode(_ unicodeScalar: UnicodeScalar, with keyScalar: UnicodeScalar) -> Character? {
        let offsetFromA = (offset(unicodeScalar) + offset(keyScalar)) % 26
        return character(from: offsetFromA)
    }

    private func decode(_ unicodeScalar: UnicodeScalar, with keyScalar: UnicodeScalar) -> Character? {
        let offsetFromA = (26 + offset(unicodeScalar) - offset(keyScalar)) % 26
        return character(from: offsetFromA)
    }

    func encode(_ plainText: String) -> String {
        let characters = zip(plainText.unicodeScalars, key.unicodeScalars).map { (plainScalar: UnicodeScalar, keyScalar: UnicodeScalar) -> Character in
            return encode(plainScalar, with: keyScalar) ?? "?"
        }

        return String(characters)
    }

    func decode(_ cipherText: String) -> String {
        let characters = zip(cipherText.unicodeScalars, key.unicodeScalars).map { (ciperScalar: UnicodeScalar, keyScalar: UnicodeScalar) -> Character in
            return decode(ciperScalar, with: keyScalar) ?? "?"
        }

        return String(characters)
    }

}

Tags:

construct:add
construct:assignment
construct:char
construct:class
construct:comment
construct:for-loop
construct:func
construct:generic-type
construct:guard
construct:if
construct:implicit-conversion
construct:import
construct:init
construct:int
construct:integral-number
construct:invocation
construct:lambda
construct:let
construct:method
construct:number
construct:optional
construct:parameter
construct:return
construct:struct
construct:subtract
construct:throw
construct:throw-expression
construct:tuple
construct:variable
construct:visibility-modifiers
paradigm:functional
paradigm:imperative
paradigm:object-oriented
technique:exceptions
technique:higher-order-functions
technique:looping
uses:UnicodeScalar
ErikSchierboom commented 11 months ago

Exercise: food-chain

Code

class FoodChain {
    /*first is the opening line in "I know an Old Lady"*/
    private static let first: [String] = [
        "a fly.",
        "a spider.\nIt wriggled and jiggled and tickled inside her.",
        "a bird.\nHow absurd to swallow a bird!",
        "a cat.\nImagine that, to swallow a cat!",
        "a dog.\nWhat a hog, to swallow a dog!",
        "a goat.\nJust opened her throat and swallowed a goat!",
        "a cow.\nI don't know how she swallowed a cow!",
        "a horse.\nShe's dead, of course!",
    ]

    /*refrain is the repeated lines in "I know an Old Lady"*/
    private static let refrain: [String] = [
        "I don't know why she swallowed the fly. Perhaps she'll die.",
        "She swallowed the spider to catch the fly.",
        "She swallowed the bird to catch the spider that wriggled and jiggled and tickled inside her.",
        "She swallowed the cat to catch the bird.",
        "She swallowed the dog to catch the cat.",
        "She swallowed the goat to catch the dog.",
        "She swallowed the cow to catch the goat.",
        "",
    ]

    /*verse sings a verse of "I know an Old Lady"*/
    static func verse(v: Int) -> String {
        let opening: String =
            "I know an old lady who swallowed "
            + first[v-1]
        let chorus: String = refrain[0..<v]
            .reverse()
            .joinWithSeparator("\n")
        return opening + (v != first.count ? "\n" + chorus : "")
    }

    /*song sings the entire "I know an Old Lady" song*/
    static func song() -> String {
        return Array(1...first.count)
            .map({verse($0)})
            .joinWithSeparator("\n\n")
    }
}

Tags:

construct:class
construct:comment
construct:initializer
construct:int
construct:interval
construct:invocation
construct:lambda
construct:let
construct:method
construct:number
construct:parameter
construct:return
construct:string
construct:subtract
construct:ternary
construct:throw
construct:tuple
construct:variable
construct:visibility-modifiers
paradigm:functional
paradigm:object-oriented
technique:exceptions
technique:higher-order-functions
ErikSchierboom commented 11 months ago

Exercise: food-chain

Code

//
//  FoodChain.swift
//  FoodChain
//
//  Created by Thierry Darrigrand on 24/04/2016.
//  Copyright © 2016 Thierry Darrigrand. All rights reserved.
//

struct FoodChain {

    static let intro = "I know an old lady who swallowed a"

    static let animals = ["fly", "spider", "bird", "cat", "dog", "goat", "cow", "horse"]

    static let wriggled = "wriggled and jiggled and tickled inside her"

    static let complements = ["I don't know why she swallowed the fly. Perhaps she'll die.", "It \(wriggled).", "How absurd to swallow a bird!", "Imagine that, to swallow a cat!", "What a hog, to swallow a dog!", "Just opened her throat and swallowed a goat!", "I don't know how she swallowed a cow!", "She's dead, of course!"]

    static func verse(n:Int)->String {
        var lines = ["\(intro) \(animals[n-1]).", complements[n-1]]
        if n == 1 || n == 8 {
            return lines.joinWithSeparator("\n")
        }

        var count = n
        while count > 1 {
            let final = count == 3 ? " that \(wriggled)" : ""
            let conclusion = "She swallowed the \(animals[count-1]) to catch the \(animals[count-2])\(final)."
            lines += [conclusion]
            count-=1
        }

        lines += [complements[0]]

        return lines.joinWithSeparator("\n")
    }

    static func song()->String {
        var song: [String] = []
        for n in 1...8 {
            song += [verse(n)]
        }

        return song.joinWithSeparator("\n\n")
    }
}

Tags:

construct:string-interpolation
construct:add-assignment
construct:assignment
construct:boolean
construct:class
construct:comment
construct:for-loop
construct:function
construct:if
construct:index-lookup
construct:initializer
construct:int
construct:interval
construct:invocation
construct:logical-or
construct:method
construct:number
construct:parameter
construct:return
construct:struct
construct:subtract
construct:ternary
construct:variable
construct:visibility-modifiers
construct:while-loop
paradigm:imperative
paradigm:object-oriented
technique:boolean-logic
technique:looping
ErikSchierboom commented 11 months ago

Exercise: binary

Code

struct Binary {
    let value:Int

    init?(_ input:String) {

        let chars = input.characters
        guard chars.filter({ return $0 != "0" && $0 != "1" }).count == 0 else { return nil }

        let bits = chars.flatMap({ $0 == "1" }).reverse()

        self.value = bits.enumerate().reduce(0, combine: { acc, tuple in

            let bit = tuple.element
            let power = tuple.index

            let add = bit ? pow(2, power) : 0
            return acc + Int(add)
        })
    }
}

func pow(a: Int, _ b: Int) -> Int {
    return Int(pow(Double(a), Double(b)))
}

extension Int {
    init?(_ binary:Binary?) {
        guard let binary = binary else { return nil }
        self.init(binary.value)
    }
}

Tags:

construct:add
construct:assignment
construct:boolean
construct:double
construct:extension
construct:floating-point-number
construct:func
construct:guard
construct:higher-order-function
construct:implicit-conversion
construct:init
construct:int
construct:integral-number
construct:invocation
construct:lambda
construct:let
construct:method
construct:number
construct:parameter
construct:return
construct:struct
construct:ternary
construct:variable
construct:visibility-modifiers
paradigm:functional
paradigm:imperative
paradigm:object-oriented
technique:higher-order-functions
ErikSchierboom commented 11 months ago

This is an automated comment

Hello :wave: Next week we're going to start using the tagging work people are doing on these. If you've already completed the work, thank you! If you've not, but intend to this week, that's great! If you're not going to get round to doing it, and you've not yet posted a comment letting us know, could you please do so, so that we can find other people to do it. Thanks!