From 71ab3f8eb62bea0886536f2fd12b7b703ea0cb2e Mon Sep 17 00:00:00 2001 From: Blaine Rothrock Date: Tue, 26 Sep 2017 15:34:03 -0700 Subject: [PATCH 001/271] algorithm proposal --- Genetic/README.markdown | 2 + Genetic/gen.swift | 179 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 181 insertions(+) create mode 100644 Genetic/README.markdown create mode 100644 Genetic/gen.swift diff --git a/Genetic/README.markdown b/Genetic/README.markdown new file mode 100644 index 000000000..7cad649cb --- /dev/null +++ b/Genetic/README.markdown @@ -0,0 +1,2 @@ +# todo +refactoring https://gist.github.com/blainerothrock/efda6e12fe10792c99c990f8ff3daeba for swift 4. Creating a tutorial and writing in more playground friendly format diff --git a/Genetic/gen.swift b/Genetic/gen.swift new file mode 100644 index 000000000..72830b8a7 --- /dev/null +++ b/Genetic/gen.swift @@ -0,0 +1,179 @@ +/* + base .. to be refactored +*/ + +import Foundation + +// HELPERS +/* + String extension to convert a string to ascii value +*/ +extension String { + var asciiArray: [UInt8] { + return unicodeScalars.filter{$0.isASCII}.map{UInt8($0.value)} + } +} + +/* + helper function to return a random character string +*/ +func randomChar() -> UInt8 { + + let letters : [UInt8] = " !\"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~".asciiArray + let len = UInt32(letters.count-1) + + let rand = Int(arc4random_uniform(len)) + return letters[rand] +} + +// END HELPERS + +let OPTIMAL:[UInt8] = "Hello, World".asciiArray +let DNA_SIZE = OPTIMAL.count +let POP_SIZE = 50 +let GENERATIONS = 5000 +let MUTATION_CHANCE = 100 + +/* + calculated the fitness based on approximate string matching + compares each character ascii value difference and adds that to a total fitness + optimal string comparsion = 0 +*/ +func calculateFitness(dna:[UInt8], optimal:[UInt8]) -> Int { + + var fitness = 0 + for c in 0...dna.count-1 { + fitness += abs(Int(dna[c]) - Int(optimal[c])) + } + return fitness +} + +/* + randomly mutate the string +*/ +func mutate(dna:[UInt8], mutationChance:Int, dnaSize:Int) -> [UInt8] { + var outputDna = dna + + for i in 0.. (dna1:[UInt8], dna2:[UInt8]) { + let pos = Int(arc4random_uniform(UInt32(dnaSize-1))) + + let dna1Index1 = dna1.index(dna1.startIndex, offsetBy: pos) + let dna2Index1 = dna2.index(dna2.startIndex, offsetBy: pos) + + return ( + [UInt8](dna1.prefix(upTo: dna1Index1) + dna2.suffix(from: dna2Index1)), + [UInt8](dna2.prefix(upTo: dna2Index1) + dna1.suffix(from: dna1Index1)) + ) +} + + +/* +returns a random population, used to start the evolution +*/ +func randomPopulation(populationSize: Int, dnaSize: Int) -> [[UInt8]] { + + let letters : [UInt8] = " !\"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~".asciiArray + let len = UInt32(letters.count) + + var pop = [[UInt8]]() + + for _ in 0.. (item:[UInt8], weight:Double) { + var weightTotal = 0.0 + for itemTuple in items { + weightTotal += itemTuple.weight; + } + + var n = Double(arc4random_uniform(UInt32(weightTotal * 1000000.0))) / 1000000.0 + + for itemTuple in items { + if n < itemTuple.weight { + return itemTuple + } + n = n - itemTuple.weight + } + return items[1] +} + +func main() { + + // generate the starting random population + var population:[[UInt8]] = randomPopulation(populationSize: POP_SIZE, dnaSize: DNA_SIZE) + // print("population: \(population), dnaSize: \(DNA_SIZE) ") + var fittest = [UInt8]() + + for generation in 0...GENERATIONS { + print("Generation \(generation) with random sample: \(String(bytes: population[0], encoding:.ascii)!)") + + var weightedPopulation = [(item:[UInt8], weight:Double)]() + + // calulcated the fitness of each individual in the population + // and add it to the weight population (weighted = 1.0/fitness) + for individual in population { + let fitnessValue = calculateFitness(dna: individual, optimal: OPTIMAL) + + let pair = ( individual, fitnessValue == 0 ? 1.0 : 1.0/Double( fitnessValue ) ) + + weightedPopulation.append(pair) + } + + population = [] + + // create a new generation using the individuals in the origional population + for _ in 0...POP_SIZE/2 { + let ind1 = weightedChoice(items: weightedPopulation) + let ind2 = weightedChoice(items: weightedPopulation) + + let offspring = crossover(dna1: ind1.item, dna2: ind2.item, dnaSize: DNA_SIZE) + + // append to the population and mutate + population.append(mutate(dna: offspring.dna1, mutationChance: MUTATION_CHANCE, dnaSize: DNA_SIZE)) + population.append(mutate(dna: offspring.dna2, mutationChance: MUTATION_CHANCE, dnaSize: DNA_SIZE)) + } + + fittest = population[0] + var minFitness = calculateFitness(dna: fittest, optimal: OPTIMAL) + + // parse the population for the fittest string + for indv in population { + let indvFitness = calculateFitness(dna: indv, optimal: OPTIMAL) + if indvFitness < minFitness { + fittest = indv + minFitness = indvFitness + } + } + if minFitness == 0 { break; } + } + print("fittest string: \(String(bytes: fittest, encoding: .ascii)!)") +} + +main() From 4b73295140df7cb645431aeb01b867f944725ef8 Mon Sep 17 00:00:00 2001 From: Jaap Wijnen Date: Thu, 26 Oct 2017 02:21:17 +0200 Subject: [PATCH 002/271] initial points lines planes commit --- .../project.pbxproj | 296 ++++++++++++++++++ .../contents.xcworkspacedata | 7 + .../Points Lines Planes/2D/Line2D.swift | 161 ++++++++++ .../Points Lines Planes/2D/Point2D.swift | 40 +++ .../Points Lines Planes/main.swift | 24 ++ Points Lines Planes/README.md | 34 ++ 6 files changed, 562 insertions(+) create mode 100644 Points Lines Planes/Points Lines Planes.xcodeproj/project.pbxproj create mode 100644 Points Lines Planes/Points Lines Planes.xcodeproj/project.xcworkspace/contents.xcworkspacedata create mode 100644 Points Lines Planes/Points Lines Planes/2D/Line2D.swift create mode 100644 Points Lines Planes/Points Lines Planes/2D/Point2D.swift create mode 100644 Points Lines Planes/Points Lines Planes/main.swift create mode 100644 Points Lines Planes/README.md diff --git a/Points Lines Planes/Points Lines Planes.xcodeproj/project.pbxproj b/Points Lines Planes/Points Lines Planes.xcodeproj/project.pbxproj new file mode 100644 index 000000000..aeba4777b --- /dev/null +++ b/Points Lines Planes/Points Lines Planes.xcodeproj/project.pbxproj @@ -0,0 +1,296 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 48; + objects = { + +/* Begin PBXBuildFile section */ + 8EA8A3BB1F9F7B6300FD8BC0 /* Point2D.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8EA8A3BA1F9F7B6300FD8BC0 /* Point2D.swift */; }; + 8EA8A3BD1F9F7B7100FD8BC0 /* Line2D.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8EA8A3BC1F9F7B7100FD8BC0 /* Line2D.swift */; }; + 8EF612481F9E00E000267358 /* main.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8EF612471F9E00E000267358 /* main.swift */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 8EF612421F9E00E000267358 /* CopyFiles */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = /usr/share/man/man1/; + dstSubfolderSpec = 0; + files = ( + ); + runOnlyForDeploymentPostprocessing = 1; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 8EA8A3BA1F9F7B6300FD8BC0 /* Point2D.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Point2D.swift; sourceTree = ""; }; + 8EA8A3BC1F9F7B7100FD8BC0 /* Line2D.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Line2D.swift; sourceTree = ""; }; + 8EF612441F9E00E000267358 /* Points Lines Planes */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = "Points Lines Planes"; sourceTree = BUILT_PRODUCTS_DIR; }; + 8EF612471F9E00E000267358 /* main.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = main.swift; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 8EF612411F9E00E000267358 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 8EA8A3C21F9F7C9000FD8BC0 /* 2D */ = { + isa = PBXGroup; + children = ( + 8EA8A3BA1F9F7B6300FD8BC0 /* Point2D.swift */, + 8EA8A3BC1F9F7B7100FD8BC0 /* Line2D.swift */, + ); + path = 2D; + sourceTree = ""; + }; + 8EF6123B1F9E00DF00267358 = { + isa = PBXGroup; + children = ( + 8EF612461F9E00E000267358 /* Points Lines Planes */, + 8EF612451F9E00E000267358 /* Products */, + ); + sourceTree = ""; + }; + 8EF612451F9E00E000267358 /* Products */ = { + isa = PBXGroup; + children = ( + 8EF612441F9E00E000267358 /* Points Lines Planes */, + ); + name = Products; + sourceTree = ""; + }; + 8EF612461F9E00E000267358 /* Points Lines Planes */ = { + isa = PBXGroup; + children = ( + 8EF612471F9E00E000267358 /* main.swift */, + 8EA8A3C21F9F7C9000FD8BC0 /* 2D */, + ); + path = "Points Lines Planes"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 8EF612431F9E00E000267358 /* Points Lines Planes */ = { + isa = PBXNativeTarget; + buildConfigurationList = 8EF6124B1F9E00E000267358 /* Build configuration list for PBXNativeTarget "Points Lines Planes" */; + buildPhases = ( + 8EF612401F9E00E000267358 /* Sources */, + 8EF612411F9E00E000267358 /* Frameworks */, + 8EF612421F9E00E000267358 /* CopyFiles */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = "Points Lines Planes"; + productName = "Points Lines Planes"; + productReference = 8EF612441F9E00E000267358 /* Points Lines Planes */; + productType = "com.apple.product-type.tool"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 8EF6123C1F9E00DF00267358 /* Project object */ = { + isa = PBXProject; + attributes = { + LastSwiftUpdateCheck = 0900; + LastUpgradeCheck = 0900; + ORGANIZATIONNAME = Workmoose; + TargetAttributes = { + 8EF612431F9E00E000267358 = { + CreatedOnToolsVersion = 9.0.1; + ProvisioningStyle = Automatic; + }; + }; + }; + buildConfigurationList = 8EF6123F1F9E00DF00267358 /* Build configuration list for PBXProject "Points Lines Planes" */; + compatibilityVersion = "Xcode 8.0"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + ); + mainGroup = 8EF6123B1F9E00DF00267358; + productRefGroup = 8EF612451F9E00E000267358 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 8EF612431F9E00E000267358 /* Points Lines Planes */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXSourcesBuildPhase section */ + 8EF612401F9E00E000267358 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 8EA8A3BB1F9F7B6300FD8BC0 /* Point2D.swift in Sources */, + 8EF612481F9E00E000267358 /* main.swift in Sources */, + 8EA8A3BD1F9F7B7100FD8BC0 /* Line2D.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + 8EF612491F9E00E000267358 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "Mac Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.13; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = macosx; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + }; + name = Debug; + }; + 8EF6124A1F9E00E000267358 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "Mac Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.13; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = macosx; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + }; + name = Release; + }; + 8EF6124C1F9E00E000267358 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = 7C4LVS3ZVC; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 4.0; + }; + name = Debug; + }; + 8EF6124D1F9E00E000267358 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = 7C4LVS3ZVC; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 4.0; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 8EF6123F1F9E00DF00267358 /* Build configuration list for PBXProject "Points Lines Planes" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 8EF612491F9E00E000267358 /* Debug */, + 8EF6124A1F9E00E000267358 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 8EF6124B1F9E00E000267358 /* Build configuration list for PBXNativeTarget "Points Lines Planes" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 8EF6124C1F9E00E000267358 /* Debug */, + 8EF6124D1F9E00E000267358 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 8EF6123C1F9E00DF00267358 /* Project object */; +} diff --git a/Points Lines Planes/Points Lines Planes.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/Points Lines Planes/Points Lines Planes.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..82bfe2b7d --- /dev/null +++ b/Points Lines Planes/Points Lines Planes.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/Points Lines Planes/Points Lines Planes/2D/Line2D.swift b/Points Lines Planes/Points Lines Planes/2D/Line2D.swift new file mode 100644 index 000000000..c92cbdbed --- /dev/null +++ b/Points Lines Planes/Points Lines Planes/2D/Line2D.swift @@ -0,0 +1,161 @@ +// +// Line2D.swift +// Points Lines Planes +// +// Created by Jaap Wijnen on 24-10-17. +// + +struct Line2D: Equatable { + + var slope: Slope + var offset: Double + var direction: Direction + + enum Slope: Equatable { + case finite(slope: Double) + case infinite(offset: Double) + + static func ==(lhs: Slope, rhs: Slope) -> Bool { + switch (lhs, rhs) { + case (.finite(let slope1), .finite(let slope2)): return slope1 == slope2 + case (.infinite(let offset1), .infinite(let offset2)): return offset1 == offset2 + default: return false + } + } + } + + enum Direction: Equatable { + case increasing + case decreasing + + static func ==(lhs: Direction, rhs: Direction) -> Bool { + switch (lhs, rhs) { + case (.increasing, .increasing): return true + case (.decreasing, .decreasing): return true + default: return false + } + } + } + + init(from p1: Point2D, to p2: Point2D) { + if p1 == p2 { fatalError("Points can not be equal when creating a line between them") } + if p1.x == p2.x { + self.slope = .infinite(offset: p1.x) + self.offset = 0 + self.direction = p1.y < p2.y ? .increasing : .decreasing + + return + } + + let slope = (p1.y - p2.y)/(p1.x - p2.x) + self.slope = .finite(slope: slope) + offset = (p1.y + p2.y - slope * (p1.x + p2.x))/2 + if slope >= 0 { + // so a horizontal line going left to right is called increasing + self.direction = p1.x < p2.x ? .increasing : .decreasing + } else { + self.direction = p1.x < p2.x ? .decreasing : .increasing + } + } + + fileprivate init(slope: Slope, offset: Double, direction: Direction) { + self.slope = slope + self.offset = offset + self.direction = direction + } + + // returns y coordinate on line for given x + func y(at x: Double) -> Double { + switch self.slope { + case .finite(let slope): + return slope * x + self.offset + case .infinite: + fatalError("y can be anywhere on vertical line") + } + } + + // returns x coordinate on line for given y + func x(at y: Double) -> Double { + switch self.slope { + case .finite(let slope): + if slope == 0 { + fatalError("x can be anywhere on horizontal line") + } + return (y - self.offset)/slope + case .infinite(let offset): + return offset + } + } + + // finds intersection point between two lines. returns nil when lines don't intersect or lie on top of each other. + func intersect(with line: Line2D) -> Point2D? { + if self == line { return nil } + switch (self.slope, line.slope) { + case (.infinite, .infinite): + // lines are either parallel or on top of each other. + return nil + case (.finite(let slope1), .finite(let slope2)): + if slope1 == slope2 { return nil } // lines are parallel + // lines are not parallel calculate intersection point + let x = (line.offset - self.offset)/(slope1 - slope2) + let y = (slope1 + slope2) * x + self.offset + line.offset + return Point2D(x: x, y: y) + case (.infinite(let offset), .finite): + // one line is vertical so we only check what y value the other line has at that point + let x = offset + let y = line.y(at: x) + return Point2D(x: x, y: y) + case (.finite, .infinite(let offset)): + // one line is vertical so we only check what y value the other line has at that point + // lines are switched with respect to case above this one + let x = offset + let y = self.y(at: x) + return Point2D(x: x, y: y) + } + } + + // returns a line perpendicular to self at the given y coordinate + // direction of perpendicular lines always changes clockwise + func perpendicularLineAt(y: Double) -> Line2D { + return perpendicularLineAt(p: Point2D(x: self.x(at: y), y: y)) + } + + // returns a line perpendicular to self at the given x coordinate + // direction of perpendicular lines always changes clockwise + func perpendicularLineAt(x: Double) -> Line2D { + return perpendicularLineAt(p: Point2D(x: x, y: self.y(at: x))) + } + + private func perpendicularLineAt(p: Point2D) -> Line2D { + switch self.slope { + case .finite(let slope): + if slope == 0 { + // line is horizontal so new line will be vertical + let dir: Direction = self.direction == .increasing ? .decreasing : .increasing + return Line2D(slope: .infinite(offset: p.x), offset: 0, direction: dir) + } + + // line is neither horizontal nor vertical + // we make a new line through the point p with new slope -1/slope + let offset = (slope + 1/slope)*p.x + self.offset + + // determine direction of new line based on direction of the old line and its slope + let dir: Direction + switch self.direction { + case .increasing: + dir = slope > 0 ? .decreasing : .increasing + case .decreasing: + dir = slope > 0 ? .increasing : .decreasing + } + return Line2D(slope: .finite(slope: -1/slope), offset: offset, direction: dir) + case .infinite: + // line is vertical so new line will be horizontal + let dir: Direction = self.direction == .increasing ? .increasing : .decreasing + return Line2D(slope: .finite(slope: 0), offset: p.y, direction: dir) + } + } + + static func ==(lhs: Line2D, rhs: Line2D) -> Bool { + return lhs.slope == rhs.slope && lhs.offset == rhs.offset && lhs.direction == rhs.direction + } +} diff --git a/Points Lines Planes/Points Lines Planes/2D/Point2D.swift b/Points Lines Planes/Points Lines Planes/2D/Point2D.swift new file mode 100644 index 000000000..f51ffd64d --- /dev/null +++ b/Points Lines Planes/Points Lines Planes/2D/Point2D.swift @@ -0,0 +1,40 @@ +// +// Point2D.swift +// Points Lines Planes +// +// Created by Jaap Wijnen on 24-10-17. +// + +struct Point2D: Equatable { + var x: Double + var y: Double + + static func ==(lhs: Point2D, rhs: Point2D) -> Bool { + return lhs.x == rhs.x && lhs.y == rhs.y + } + + // returns true if point is on or right of line + func isRight(of line: Line2D) -> Bool { + switch line.slope { + case .finite: + let y = line.y(at: self.x) + switch line.direction { + case .increasing: + return y >= self.y + case .decreasing: + return y <= self.y + } + case .infinite(let offset): + switch line.direction { + case .increasing: + return self.x >= offset + case .decreasing: + return self.x <= offset + } + } + } + + func isLeft(of line: Line2D) -> Bool { + return !self.isRight(of: line) + } +} diff --git a/Points Lines Planes/Points Lines Planes/main.swift b/Points Lines Planes/Points Lines Planes/main.swift new file mode 100644 index 000000000..02137fc9d --- /dev/null +++ b/Points Lines Planes/Points Lines Planes/main.swift @@ -0,0 +1,24 @@ +// +// main.swift +// Points Lines Planes +// +// Created by Jaap Wijnen on 23-10-17. +// + +let p0 = Point2D(x: 0, y: 2) +let p1 = Point2D(x: 1, y: 1) +let p2 = Point2D(x: 1, y: 3) +let p3 = Point2D(x: 3, y: 1) +let p4 = Point2D(x: 3, y: 3) + +let horLine = Line2D(from: p1, to: p3) +let verLine = Line2D(from: p1, to: p2) +let line45 = Line2D(from: p1, to: p4) + +print(horLine.intersect(with: verLine)) +print(p0.isRight(of: line45)) +print(p0.isRight(of: horLine)) +print(p0.isRight(of: verLine)) +let lineperp = horLine.perpendicularLineAt(x: 2) +print(lineperp) + diff --git a/Points Lines Planes/README.md b/Points Lines Planes/README.md new file mode 100644 index 000000000..23c965978 --- /dev/null +++ b/Points Lines Planes/README.md @@ -0,0 +1,34 @@ +# Points Lines (Planes) +This implements data structures for points lines and planes(not yet) in (for now) 2D space and a few functions to play around with them. This was originally written to improve on the Convex Hull algorithm but I thought it might be a nice addition in itself. Im planning to add 3D implementations as well. + +# implementation +Two `struct`s are implemented the `Point2D` and `Line2D`. + +``` +struct Point2D: { + var x: Double + var y: double +} +``` + +``` +struct Line2D { + var slope: Slope + var offset: Double + var direction: Direction +} +``` +Here `Slope` is an enum to account for vertical lines. +slope is infinite for vertical lines, offset is the x coordinate where the line crosses the line `y=0`. +slope is finite for any other line and contains a double with the actual value of the slope. +``` +enum Slope { + case finite(slope: Double) + case infinite(offset: Double) +} +``` +`Line2D` also contains a `Direction` enum. This is introduced in order to make lines directional in order to be able to determine what is left and right of a certain line. It is `.increasing` if the line points in positive y direction and `.decreasing` if it points in the negative y direction. + +`Line2D`'s offset is the the y-coordinate where the line crosses the vertical x=0 line + +*Written for the Swift Algorithm Club by Jaap Wijnen.* From 7f6f5a5a56baa1a1bb6854dd2a29699f1be2c558 Mon Sep 17 00:00:00 2001 From: Jaap Wijnen Date: Thu, 26 Oct 2017 02:40:29 +0200 Subject: [PATCH 003/271] typo --- Points Lines Planes/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Points Lines Planes/README.md b/Points Lines Planes/README.md index 23c965978..2d36667ec 100644 --- a/Points Lines Planes/README.md +++ b/Points Lines Planes/README.md @@ -29,6 +29,6 @@ enum Slope { ``` `Line2D` also contains a `Direction` enum. This is introduced in order to make lines directional in order to be able to determine what is left and right of a certain line. It is `.increasing` if the line points in positive y direction and `.decreasing` if it points in the negative y direction. -`Line2D`'s offset is the the y-coordinate where the line crosses the vertical x=0 line +`Line2D`'s offset is the the y-coordinate where the line crosses the vertical `x=0` line. *Written for the Swift Algorithm Club by Jaap Wijnen.* From 02d583e8be5267707a8d37a8e2b3cc68d6bae1c5 Mon Sep 17 00:00:00 2001 From: remlostime Date: Sat, 29 Jul 2017 08:58:05 -0700 Subject: [PATCH 004/271] Improvement of Red Black Tree * Add count(), allElements(), isEmpty() functions * Make the config right for RBTree in workspace * Create a separate class for RBTree --- .../Sources/RedBlackTree.swift | 1347 +++++++++-------- Red-Black Tree/RedBlackTree.swift | 795 ++++++++++ 2 files changed, 1491 insertions(+), 651 deletions(-) create mode 100644 Red-Black Tree/RedBlackTree.swift diff --git a/Red-Black Tree/RedBlackTree.playground/Sources/RedBlackTree.swift b/Red-Black Tree/RedBlackTree.playground/Sources/RedBlackTree.swift index 59633031d..fc0411b42 100644 --- a/Red-Black Tree/RedBlackTree.playground/Sources/RedBlackTree.swift +++ b/Red-Black Tree/RedBlackTree.playground/Sources/RedBlackTree.swift @@ -21,730 +21,775 @@ import Foundation private enum RBTreeColor { - case red - case black + case red + case black } private enum RotationDirection { - case left - case right + case left + case right } // MARK: - RBNode public class RBTreeNode: Equatable { - public typealias RBNode = RBTreeNode - - fileprivate var color: RBTreeColor = .black - fileprivate var key: T? - var leftChild: RBNode? - var rightChild: RBNode? - fileprivate weak var parent: RBNode? - - public init(key: T?, leftChild: RBNode?, rightChild: RBNode?, parent: RBNode?) { - self.key = key - self.leftChild = leftChild - self.rightChild = rightChild - self.parent = parent - - self.leftChild?.parent = self - self.rightChild?.parent = self - } - - public convenience init(key: T?) { - self.init(key: key, leftChild: RBNode(), rightChild: RBNode(), parent: RBNode()) - } - - // For initialising the nullLeaf - public convenience init() { - self.init(key: nil, leftChild: nil, rightChild: nil, parent: nil) - self.color = .black - } - - var isRoot: Bool { - return parent == nil - } - - var isLeaf: Bool { - return rightChild == nil && leftChild == nil - } - - var isNullLeaf: Bool { - return key == nil && isLeaf && color == .black - } - - var isLeftChild: Bool { - return parent?.leftChild === self - } - - var isRightChild: Bool { - return parent?.rightChild === self - } - - var grandparent: RBNode? { - return parent?.parent - } - - var sibling: RBNode? { - if isLeftChild { - return parent?.rightChild - } else { - return parent?.leftChild - } - } - - var uncle: RBNode? { - return parent?.sibling - } + public typealias RBNode = RBTreeNode + + fileprivate var color: RBTreeColor = .black + fileprivate var key: T? + var leftChild: RBNode? + var rightChild: RBNode? + fileprivate weak var parent: RBNode? + + public init(key: T?, leftChild: RBNode?, rightChild: RBNode?, parent: RBNode?) { + self.key = key + self.leftChild = leftChild + self.rightChild = rightChild + self.parent = parent + + self.leftChild?.parent = self + self.rightChild?.parent = self + } + + public convenience init(key: T?) { + self.init(key: key, leftChild: RBNode(), rightChild: RBNode(), parent: RBNode()) + } + + // For initialising the nullLeaf + public convenience init() { + self.init(key: nil, leftChild: nil, rightChild: nil, parent: nil) + self.color = .black + } + + var isRoot: Bool { + return parent == nil + } + + var isLeaf: Bool { + return rightChild == nil && leftChild == nil + } + + var isNullLeaf: Bool { + return key == nil && isLeaf && color == .black + } + + var isLeftChild: Bool { + return parent?.leftChild === self + } + + var isRightChild: Bool { + return parent?.rightChild === self + } + + var grandparent: RBNode? { + return parent?.parent + } + + var sibling: RBNode? { + if isLeftChild { + return parent?.rightChild + } else { + return parent?.leftChild + } + } + + var uncle: RBNode? { + return parent?.sibling + } } // MARK: - RedBlackTree public class RedBlackTree { - public typealias RBNode = RBTreeNode - - fileprivate(set) var root: RBNode - fileprivate(set) var size = 0 - fileprivate let nullLeaf = RBNode() - - public init() { - root = nullLeaf - } + public typealias RBNode = RBTreeNode + + fileprivate(set) var root: RBNode + fileprivate(set) var size = 0 + fileprivate let nullLeaf = RBNode() + fileprivate let allowDuplicateNode: Bool + + public init(_ allowDuplicateNode: Bool = false) { + root = nullLeaf + self.allowDuplicateNode = allowDuplicateNode + } +} + +// MARK: - Size + +extension RedBlackTree { + public func count() -> Int { + return size + } + + public func isEmpty() -> Bool { + return size == 0 + } + + public func allElements() -> [T] { + var nodes: [T] = [] + + getAllElements(node: root, nodes: &nodes) + + return nodes + } + + private func getAllElements(node: RBTreeNode, nodes: inout [T]) { + guard !node.isNullLeaf else { + return + } + + if let left = node.leftChild { + getAllElements(node: left, nodes: &nodes) + } + + if let key = node.key { + nodes.append(key) + } + + if let right = node.rightChild { + getAllElements(node: right, nodes: &nodes) + } + } } // MARK: - Equatable protocol extension RBTreeNode { - static public func == (lhs: RBTreeNode, rhs: RBTreeNode) -> Bool { - return lhs.key == rhs.key - } + static public func == (lhs: RBTreeNode, rhs: RBTreeNode) -> Bool { + return lhs.key == rhs.key + } } // MARK: - Finding a nodes successor extension RBTreeNode { - /* - * Returns the inorder successor node of a node - * The successor is a node with the next larger key value of the current node - */ - public func getSuccessor() -> RBNode? { - // If node has right child: successor min of this right tree - if let rightChild = self.rightChild { - if !rightChild.isNullLeaf { - return rightChild.minimum() - } - } - // Else go upward until node left child - var currentNode = self - var parent = currentNode.parent - while currentNode.isRightChild { - if let parent = parent { - currentNode = parent - } - parent = currentNode.parent - } - return parent - } + /* + * Returns the inorder successor node of a node + * The successor is a node with the next larger key value of the current node + */ + public func getSuccessor() -> RBNode? { + // If node has right child: successor min of this right tree + if let rightChild = self.rightChild { + if !rightChild.isNullLeaf { + return rightChild.minimum() + } + } + // Else go upward until node left child + var currentNode = self + var parent = currentNode.parent + while currentNode.isRightChild { + if let parent = parent { + currentNode = parent + } + parent = currentNode.parent + } + return parent + } } // MARK: - Searching extension RBTreeNode { - /* - * Returns the node with the minimum key of the current subtree - */ - public func minimum() -> RBNode? { - if let leftChild = leftChild { - if !leftChild.isNullLeaf { - return leftChild.minimum() - } - return self - } - return self - } - - /* - * Returns the node with the maximum key of the current subtree - */ - public func maximum() -> RBNode? { - if let rightChild = rightChild { - if !rightChild.isNullLeaf { - return rightChild.maximum() - } - return self - } - return self - } + /* + * Returns the node with the minimum key of the current subtree + */ + public func minimum() -> RBNode? { + if let leftChild = leftChild { + if !leftChild.isNullLeaf { + return leftChild.minimum() + } + return self + } + return self + } + + /* + * Returns the node with the maximum key of the current subtree + */ + public func maximum() -> RBNode? { + if let rightChild = rightChild { + if !rightChild.isNullLeaf { + return rightChild.maximum() + } + return self + } + return self + } } extension RedBlackTree { - /* - * Returns the node with the given key |input| if existing - */ - public func search(input: T) -> RBNode? { - return search(key: input, node: root) - } - - /* - * Returns the node with given |key| in subtree of |node| - */ - fileprivate func search(key: T, node: RBNode?) -> RBNode? { - // If node nil -> key not found - guard let node = node else { - return nil - } - // If node is nullLeaf == semantically same as if nil - if !node.isNullLeaf { - if let nodeKey = node.key { - // Node found - if key == nodeKey { - return node - } else if key < nodeKey { - return search(key: key, node: node.leftChild) - } else { - return search(key: key, node: node.rightChild) + /* + * Returns the node with the given key |input| if existing + */ + public func search(input: T) -> RBNode? { + return search(key: input, node: root) + } + + /* + * Returns the node with given |key| in subtree of |node| + */ + fileprivate func search(key: T, node: RBNode?) -> RBNode? { + // If node nil -> key not found + guard let node = node else { + return nil + } + // If node is nullLeaf == semantically same as if nil + if !node.isNullLeaf { + if let nodeKey = node.key { + // Node found + if key == nodeKey { + return node + } else if key < nodeKey { + return search(key: key, node: node.leftChild) + } else { + return search(key: key, node: node.rightChild) + } + } } - } + return nil } - return nil - } } // MARK: - Finding maximum and minimum value extension RedBlackTree { - /* - * Returns the minimum key value of the whole tree - */ - public func minValue() -> T? { - guard let minNode = root.minimum() else { - return nil - } - return minNode.key - } - - /* - * Returns the maximum key value of the whole tree - */ - public func maxValue() -> T? { - guard let maxNode = root.maximum() else { - return nil - } - return maxNode.key - } + /* + * Returns the minimum key value of the whole tree + */ + public func minValue() -> T? { + guard let minNode = root.minimum() else { + return nil + } + return minNode.key + } + + /* + * Returns the maximum key value of the whole tree + */ + public func maxValue() -> T? { + guard let maxNode = root.maximum() else { + return nil + } + return maxNode.key + } } // MARK: - Inserting new nodes extension RedBlackTree { - /* - * Insert a node with key |key| into the tree - * 1. Perform normal insert operation as in a binary search tree - * 2. Fix red-black properties - * Runntime: O(log n) - */ - public func insert(key: T) { - if root.isNullLeaf { - root = RBNode(key: key) - } else { - insert(input: RBNode(key: key), node: root) - } - - size += 1 - } - - /* - * Nearly identical insert operation as in a binary search tree - * Differences: All nil pointers are replaced by the nullLeaf, we color the inserted node red, - * after inserting we call insertFixup to maintain the red-black properties - */ - private func insert(input: RBNode, node: RBNode) { - guard let inputKey = input.key, let nodeKey = node.key else { - return - } - if inputKey < nodeKey { - guard let child = node.leftChild else { - addAsLeftChild(child: input, parent: node) - return - } - if child.isNullLeaf { - addAsLeftChild(child: input, parent: node) - } else { - insert(input: input, node: child) - } - } else { - guard let child = node.rightChild else { - addAsRightChild(child: input, parent: node) - return - } - if child.isNullLeaf { - addAsRightChild(child: input, parent: node) - } else { - insert(input: input, node: child) - } - } - } - - private func addAsLeftChild(child: RBNode, parent: RBNode) { - parent.leftChild = child - child.parent = parent - child.color = .red - insertFixup(node: child) - } - - private func addAsRightChild(child: RBNode, parent: RBNode) { - parent.rightChild = child - child.parent = parent - child.color = .red - insertFixup(node: child) - } - - /* - * Fixes possible violations of the red-black property after insertion - * Only violation of red-black properties occurs at inserted node |z| and z.parent - * We have 3 distinct cases: case 1, 2a and 2b - * - case 1: may repeat, but only h/2 steps, where h is the height of the tree - * - case 2a -> case 2b -> red-black tree - * - case 2b -> red-black tree - */ - private func insertFixup(node z: RBNode) { - if !z.isNullLeaf { - guard let parentZ = z.parent else { - return - } - // If both |z| and his parent are red -> violation of red-black property -> need to fix it - if parentZ.color == .red { - guard let uncle = z.uncle else { - return - } - // Case 1: Uncle red -> recolor + move z - if uncle.color == .red { - parentZ.color = .black - uncle.color = .black - if let grandparentZ = parentZ.parent { - grandparentZ.color = .red - // Move z to grandparent and check again - insertFixup(node: grandparentZ) - } - } - // Case 2: Uncle black - else { - var zNew = z - // Case 2.a: z right child -> rotate - if parentZ.isLeftChild && z.isRightChild { - zNew = parentZ - leftRotate(node: zNew) - } else if parentZ.isRightChild && z.isLeftChild { - zNew = parentZ - rightRotate(node: zNew) - } - // Case 2.b: z left child -> recolor + rotate - zNew.parent?.color = .black - if let grandparentZnew = zNew.grandparent { - grandparentZnew.color = .red - if z.isLeftChild { - rightRotate(node: grandparentZnew) + /* + * Insert a node with key |key| into the tree + * 1. Perform normal insert operation as in a binary search tree + * 2. Fix red-black properties + * Runntime: O(log n) + */ + public func insert(key: T) { + // If key must be unique and find the key already existed, quit + if search(input: key) != nil && !allowDuplicateNode { + return + } + + if root.isNullLeaf { + root = RBNode(key: key) + } else { + insert(input: RBNode(key: key), node: root) + } + + size += 1 + } + + /* + * Nearly identical insert operation as in a binary search tree + * Differences: All nil pointers are replaced by the nullLeaf, we color the inserted node red, + * after inserting we call insertFixup to maintain the red-black properties + */ + private func insert(input: RBNode, node: RBNode) { + guard let inputKey = input.key, let nodeKey = node.key else { + return + } + if inputKey < nodeKey { + guard let child = node.leftChild else { + addAsLeftChild(child: input, parent: node) + return + } + if child.isNullLeaf { + addAsLeftChild(child: input, parent: node) + } else { + insert(input: input, node: child) + } + } else { + guard let child = node.rightChild else { + addAsRightChild(child: input, parent: node) + return + } + if child.isNullLeaf { + addAsRightChild(child: input, parent: node) } else { - leftRotate(node: grandparentZnew) + insert(input: input, node: child) } - // We have a valid red-black-tree - } } - } } - root.color = .black - } + + private func addAsLeftChild(child: RBNode, parent: RBNode) { + parent.leftChild = child + child.parent = parent + child.color = .red + insertFixup(node: child) + } + + private func addAsRightChild(child: RBNode, parent: RBNode) { + parent.rightChild = child + child.parent = parent + child.color = .red + insertFixup(node: child) + } + + /* + * Fixes possible violations of the red-black property after insertion + * Only violation of red-black properties occurs at inserted node |z| and z.parent + * We have 3 distinct cases: case 1, 2a and 2b + * - case 1: may repeat, but only h/2 steps, where h is the height of the tree + * - case 2a -> case 2b -> red-black tree + * - case 2b -> red-black tree + */ + private func insertFixup(node z: RBNode) { + if !z.isNullLeaf { + guard let parentZ = z.parent else { + return + } + // If both |z| and his parent are red -> violation of red-black property -> need to fix it + if parentZ.color == .red { + guard let uncle = z.uncle else { + return + } + // Case 1: Uncle red -> recolor + move z + if uncle.color == .red { + parentZ.color = .black + uncle.color = .black + if let grandparentZ = parentZ.parent { + grandparentZ.color = .red + // Move z to grandparent and check again + insertFixup(node: grandparentZ) + } + } + // Case 2: Uncle black + else { + var zNew = z + // Case 2.a: z right child -> rotate + if parentZ.isLeftChild && z.isRightChild { + zNew = parentZ + leftRotate(node: zNew) + } else if parentZ.isRightChild && z.isLeftChild { + zNew = parentZ + rightRotate(node: zNew) + } + // Case 2.b: z left child -> recolor + rotate + zNew.parent?.color = .black + if let grandparentZnew = zNew.grandparent { + grandparentZnew.color = .red + if z.isLeftChild { + rightRotate(node: grandparentZnew) + } else { + leftRotate(node: grandparentZnew) + } + // We have a valid red-black-tree + } + } + } + } + root.color = .black + } } // MARK: - Deleting a node extension RedBlackTree { - /* - * Delete a node with key |key| from the tree - * 1. Perform standard delete operation as in a binary search tree - * 2. Fix red-black properties - * Runntime: O(log n) - */ - public func delete(key: T) { - if size == 1 { - root = nullLeaf - size -= 1 - } else if let node = search(key: key, node: root) { - if !node.isNullLeaf { - delete(node: node) - size -= 1 - } - } - } - - /* - * Nearly identical delete operation as in a binary search tree - * Differences: All nil pointers are replaced by the nullLeaf, - * after deleting we call insertFixup to maintain the red-black properties if the delted node was - * black (as if it was red -> no violation of red-black properties) - */ - private func delete(node z: RBNode) { - var nodeY = RBNode() - var nodeX = RBNode() - if let leftChild = z.leftChild, let rightChild = z.rightChild { - if leftChild.isNullLeaf || rightChild.isNullLeaf { - nodeY = z - } else { - if let successor = z.getSuccessor() { - nodeY = successor - } - } - } - if let leftChild = nodeY.leftChild { - if !leftChild.isNullLeaf { - nodeX = leftChild - } else if let rightChild = nodeY.rightChild { - nodeX = rightChild - } - } - nodeX.parent = nodeY.parent - if let parentY = nodeY.parent { - // Should never be the case, as parent of root = nil - if parentY.isNullLeaf { - root = nodeX - } else { - if nodeY.isLeftChild { - parentY.leftChild = nodeX + /* + * Delete a node with key |key| from the tree + * 1. Perform standard delete operation as in a binary search tree + * 2. Fix red-black properties + * Runntime: O(log n) + */ + public func delete(key: T) { + if size == 1 { + root = nullLeaf + size -= 1 + } else if let node = search(key: key, node: root) { + if !node.isNullLeaf { + delete(node: node) + size -= 1 + } + } + } + + /* + * Nearly identical delete operation as in a binary search tree + * Differences: All nil pointers are replaced by the nullLeaf, + * after deleting we call insertFixup to maintain the red-black properties if the delted node was + * black (as if it was red -> no violation of red-black properties) + */ + private func delete(node z: RBNode) { + var nodeY = RBNode() + var nodeX = RBNode() + if let leftChild = z.leftChild, let rightChild = z.rightChild { + if leftChild.isNullLeaf || rightChild.isNullLeaf { + nodeY = z + } else { + if let successor = z.getSuccessor() { + nodeY = successor + } + } + } + if let leftChild = nodeY.leftChild { + if !leftChild.isNullLeaf { + nodeX = leftChild + } else if let rightChild = nodeY.rightChild { + nodeX = rightChild + } + } + nodeX.parent = nodeY.parent + if let parentY = nodeY.parent { + // Should never be the case, as parent of root = nil + if parentY.isNullLeaf { + root = nodeX + } else { + if nodeY.isLeftChild { + parentY.leftChild = nodeX + } else { + parentY.rightChild = nodeX + } + } } else { - parentY.rightChild = nodeX - } - } - } else { - root = nodeX - } - if nodeY != z { - z.key = nodeY.key - } - // If sliced out node was red -> nothing to do as red-black-property holds - // If it was black -> fix red-black-property - if nodeY.color == .black { - deleteFixup(node: nodeX) - } - } - - /* - * Fixes possible violations of the red-black property after deletion - * We have w distinct cases: only case 2 may repeat, but only h many steps, where h is the height - * of the tree - * - case 1 -> case 2 -> red-black tree - * case 1 -> case 3 -> case 4 -> red-black tree - * case 1 -> case 4 -> red-black tree - * - case 3 -> case 4 -> red-black tree - * - case 4 -> red-black tree - */ - private func deleteFixup(node x: RBNode) { - var xTmp = x - if !x.isRoot && x.color == .black { - guard var sibling = x.sibling else { - return - } - // Case 1: Sibling of x is red - if sibling.color == .red { - // Recolor - sibling.color = .black - if let parentX = x.parent { - parentX.color = .red - // Rotation - if x.isLeftChild { - leftRotate(node: parentX) - } else { - rightRotate(node: parentX) - } - // Update sibling - if let sibl = x.sibling { - sibling = sibl - } - } - } - // Case 2: Sibling is black with two black children - if sibling.leftChild?.color == .black && sibling.rightChild?.color == .black { - // Recolor - sibling.color = .red - // Move fake black unit upwards - if let parentX = x.parent { - deleteFixup(node: parentX) - } - // We have a valid red-black-tree - } else { - // Case 3: a. Sibling black with one black child to the right - if x.isLeftChild && sibling.rightChild?.color == .black { - // Recolor - sibling.leftChild?.color = .black - sibling.color = .red - // Rotate - rightRotate(node: sibling) - // Update sibling of x - if let sibl = x.sibling { - sibling = sibl - } - } - // Still case 3: b. One black child to the left - else if x.isRightChild && sibling.leftChild?.color == .black { - // Recolor - sibling.rightChild?.color = .black - sibling.color = .red - // Rotate - leftRotate(node: sibling) - // Update sibling of x - if let sibl = x.sibling { - sibling = sibl - } - } - // Case 4: Sibling is black with red right child - // Recolor - if let parentX = x.parent { - sibling.color = parentX.color - parentX.color = .black - // a. x left and sibling with red right child - if x.isLeftChild { - sibling.rightChild?.color = .black - // Rotate - leftRotate(node: parentX) - } - // b. x right and sibling with red left child - else { - sibling.leftChild?.color = .black - //Rotate - rightRotate(node: parentX) - } - // We have a valid red-black-tree - xTmp = root - } - } - } - xTmp.color = .black - } + root = nodeX + } + if nodeY != z { + z.key = nodeY.key + } + // If sliced out node was red -> nothing to do as red-black-property holds + // If it was black -> fix red-black-property + if nodeY.color == .black { + deleteFixup(node: nodeX) + } + } + + /* + * Fixes possible violations of the red-black property after deletion + * We have w distinct cases: only case 2 may repeat, but only h many steps, where h is the height + * of the tree + * - case 1 -> case 2 -> red-black tree + * case 1 -> case 3 -> case 4 -> red-black tree + * case 1 -> case 4 -> red-black tree + * - case 3 -> case 4 -> red-black tree + * - case 4 -> red-black tree + */ + private func deleteFixup(node x: RBNode) { + var xTmp = x + if !x.isRoot && x.color == .black { + guard var sibling = x.sibling else { + return + } + // Case 1: Sibling of x is red + if sibling.color == .red { + // Recolor + sibling.color = .black + if let parentX = x.parent { + parentX.color = .red + // Rotation + if x.isLeftChild { + leftRotate(node: parentX) + } else { + rightRotate(node: parentX) + } + // Update sibling + if let sibl = x.sibling { + sibling = sibl + } + } + } + // Case 2: Sibling is black with two black children + if sibling.leftChild?.color == .black && sibling.rightChild?.color == .black { + // Recolor + sibling.color = .red + // Move fake black unit upwards + if let parentX = x.parent { + deleteFixup(node: parentX) + } + // We have a valid red-black-tree + } else { + // Case 3: a. Sibling black with one black child to the right + if x.isLeftChild && sibling.rightChild?.color == .black { + // Recolor + sibling.leftChild?.color = .black + sibling.color = .red + // Rotate + rightRotate(node: sibling) + // Update sibling of x + if let sibl = x.sibling { + sibling = sibl + } + } + // Still case 3: b. One black child to the left + else if x.isRightChild && sibling.leftChild?.color == .black { + // Recolor + sibling.rightChild?.color = .black + sibling.color = .red + // Rotate + leftRotate(node: sibling) + // Update sibling of x + if let sibl = x.sibling { + sibling = sibl + } + } + // Case 4: Sibling is black with red right child + // Recolor + if let parentX = x.parent { + sibling.color = parentX.color + parentX.color = .black + // a. x left and sibling with red right child + if x.isLeftChild { + sibling.rightChild?.color = .black + // Rotate + leftRotate(node: parentX) + } + // b. x right and sibling with red left child + else { + sibling.leftChild?.color = .black + //Rotate + rightRotate(node: parentX) + } + // We have a valid red-black-tree + xTmp = root + } + } + } + xTmp.color = .black + } } // MARK: - Rotation extension RedBlackTree { - /* - * Left rotation around node x - * Assumes that x.rightChild y is not a nullLeaf, rotates around the link from x to y, - * makes y the new root of the subtree with x as y's left child and y's left child as x's right - * child, where n = a node, [n] = a subtree - * | | - * x y - * / \ ~> / \ - * [A] y x [C] - * / \ / \ - * [B] [C] [A] [B] - */ - fileprivate func leftRotate(node x: RBNode) { - rotate(node: x, direction: .left) - } - - /* - * Right rotation around node y - * Assumes that y.leftChild x is not a nullLeaf, rotates around the link from y to x, - * makes x the new root of the subtree with y as x's right child and x's right child as y's left - * child, where n = a node, [n] = a subtree - * | | - * x y - * / \ <~ / \ - * [A] y x [C] - * / \ / \ - * [B] [C] [A] [B] - */ - fileprivate func rightRotate(node x: RBNode) { - rotate(node: x, direction: .right) - } - - /* - * Rotation around a node x - * Is a local operation preserving the binary-search-tree property that only exchanges pointers. - * Runntime: O(1) - */ - private func rotate(node x: RBNode, direction: RotationDirection) { - var nodeY: RBNode? = RBNode() - - // Set |nodeY| and turn |nodeY|'s left/right subtree into |x|'s right/left subtree - switch direction { - case .left: - nodeY = x.rightChild - x.rightChild = nodeY?.leftChild - x.rightChild?.parent = x - case .right: - nodeY = x.leftChild - x.leftChild = nodeY?.rightChild - x.leftChild?.parent = x - } - - // Link |x|'s parent to nodeY - nodeY?.parent = x.parent - if x.isRoot { - if let node = nodeY { - root = node - } - } else if x.isLeftChild { - x.parent?.leftChild = nodeY - } else if x.isRightChild { - x.parent?.rightChild = nodeY - } - - // Put |x| on |nodeY|'s left - switch direction { - case .left: - nodeY?.leftChild = x - case .right: - nodeY?.rightChild = x - } - x.parent = nodeY - } + /* + * Left rotation around node x + * Assumes that x.rightChild y is not a nullLeaf, rotates around the link from x to y, + * makes y the new root of the subtree with x as y's left child and y's left child as x's right + * child, where n = a node, [n] = a subtree + * | | + * x y + * / \ ~> / \ + * [A] y x [C] + * / \ / \ + * [B] [C] [A] [B] + */ + fileprivate func leftRotate(node x: RBNode) { + rotate(node: x, direction: .left) + } + + /* + * Right rotation around node y + * Assumes that y.leftChild x is not a nullLeaf, rotates around the link from y to x, + * makes x the new root of the subtree with y as x's right child and x's right child as y's left + * child, where n = a node, [n] = a subtree + * | | + * x y + * / \ <~ / \ + * [A] y x [C] + * / \ / \ + * [B] [C] [A] [B] + */ + fileprivate func rightRotate(node x: RBNode) { + rotate(node: x, direction: .right) + } + + /* + * Rotation around a node x + * Is a local operation preserving the binary-search-tree property that only exchanges pointers. + * Runntime: O(1) + */ + private func rotate(node x: RBNode, direction: RotationDirection) { + var nodeY: RBNode? = RBNode() + + // Set |nodeY| and turn |nodeY|'s left/right subtree into |x|'s right/left subtree + switch direction { + case .left: + nodeY = x.rightChild + x.rightChild = nodeY?.leftChild + x.rightChild?.parent = x + case .right: + nodeY = x.leftChild + x.leftChild = nodeY?.rightChild + x.leftChild?.parent = x + } + + // Link |x|'s parent to nodeY + nodeY?.parent = x.parent + if x.isRoot { + if let node = nodeY { + root = node + } + } else if x.isLeftChild { + x.parent?.leftChild = nodeY + } else if x.isRightChild { + x.parent?.rightChild = nodeY + } + + // Put |x| on |nodeY|'s left + switch direction { + case .left: + nodeY?.leftChild = x + case .right: + nodeY?.rightChild = x + } + x.parent = nodeY + } } // MARK: - Verify extension RedBlackTree { - /* - * Verifies that the existing tree fulfills all red-black properties - * Returns true if the tree is a valid red-black tree, false otherwise - */ - public func verify() -> Bool { - if root.isNullLeaf { - print("The tree is empty") - return true - } - return property2() && property4() && property5() - } - - // Property 1: Every node is either red or black -> fullfilled through setting node.color of type - // RBTreeColor - - // Property 2: The root is black - private func property2() -> Bool { - if root.color == .red { - print("Property-Error: Root is red") - return false - } - return true - } - - // Property 3: Every nullLeaf is black -> fullfilled through initialising nullLeafs with color = black - - // Property 4: If a node is red, then both its children are black - private func property4() -> Bool { - return property4(node: root) - } - - private func property4(node: RBNode) -> Bool { - if node.isNullLeaf { - return true - } - if let leftChild = node.leftChild, let rightChild = node.rightChild { - if node.color == .red { - if !leftChild.isNullLeaf && leftChild.color == .red { - print("Property-Error: Red node with key \(String(describing: node.key)) has red left child") - return false - } - if !rightChild.isNullLeaf && rightChild.color == .red { - print("Property-Error: Red node with key \(String(describing: node.key)) has red right child") - return false - } - } - return property4(node: leftChild) && property4(node: rightChild) - } - return false - } - - // Property 5: For each node, all paths from the node to descendant leaves contain the same number - // of black nodes (same blackheight) - private func property5() -> Bool { - if property5(node: root) == -1 { - return false - } else { - return true - } - } - - private func property5(node: RBNode) -> Int { - if node.isNullLeaf { - return 0 - } - guard let leftChild = node.leftChild, let rightChild = node.rightChild else { - return -1 - } - let left = property5(node: leftChild) - let right = property5(node: rightChild) - - if left == -1 || right == -1 { - return -1 - } else if left == right { - let addedHeight = node.color == .black ? 1 : 0 - return left + addedHeight - } else { - print("Property-Error: Black height violated at node with key \(String(describing: node.key))") - return -1 - } - } + /* + * Verifies that the existing tree fulfills all red-black properties + * Returns true if the tree is a valid red-black tree, false otherwise + */ + public func verify() -> Bool { + if root.isNullLeaf { + print("The tree is empty") + return true + } + return property2() && property4() && property5() + } + + // Property 1: Every node is either red or black -> fullfilled through setting node.color of type + // RBTreeColor + + // Property 2: The root is black + private func property2() -> Bool { + if root.color == .red { + print("Property-Error: Root is red") + return false + } + return true + } + + // Property 3: Every nullLeaf is black -> fullfilled through initialising nullLeafs with color = black + + // Property 4: If a node is red, then both its children are black + private func property4() -> Bool { + return property4(node: root) + } + + private func property4(node: RBNode) -> Bool { + if node.isNullLeaf { + return true + } + if let leftChild = node.leftChild, let rightChild = node.rightChild { + if node.color == .red { + if !leftChild.isNullLeaf && leftChild.color == .red { + print("Property-Error: Red node with key \(String(describing: node.key)) has red left child") + return false + } + if !rightChild.isNullLeaf && rightChild.color == .red { + print("Property-Error: Red node with key \(String(describing: node.key)) has red right child") + return false + } + } + return property4(node: leftChild) && property4(node: rightChild) + } + return false + } + + // Property 5: For each node, all paths from the node to descendant leaves contain the same number + // of black nodes (same blackheight) + private func property5() -> Bool { + if property5(node: root) == -1 { + return false + } else { + return true + } + } + + private func property5(node: RBNode) -> Int { + if node.isNullLeaf { + return 0 + } + guard let leftChild = node.leftChild, let rightChild = node.rightChild else { + return -1 + } + let left = property5(node: leftChild) + let right = property5(node: rightChild) + + if left == -1 || right == -1 { + return -1 + } else if left == right { + let addedHeight = node.color == .black ? 1 : 0 + return left + addedHeight + } else { + print("Property-Error: Black height violated at node with key \(String(describing: node.key))") + return -1 + } + } } // MARK: - Debugging extension RBTreeNode: CustomDebugStringConvertible { - public var debugDescription: String { - var s = "" - if isNullLeaf { - s = "nullLeaf" - } else { - if let key = key { - s = "key: \(key)" - } else { - s = "key: nil" - } - if let parent = parent { - s += ", parent: \(String(describing: parent.key))" - } - if let left = leftChild { - s += ", left = [" + left.debugDescription + "]" - } - if let right = rightChild { - s += ", right = [" + right.debugDescription + "]" - } - s += ", color = \(color)" - } - return s - } + public var debugDescription: String { + var s = "" + if isNullLeaf { + s = "nullLeaf" + } else { + if let key = key { + s = "key: \(key)" + } else { + s = "key: nil" + } + if let parent = parent { + s += ", parent: \(String(describing: parent.key))" + } + if let left = leftChild { + s += ", left = [" + left.debugDescription + "]" + } + if let right = rightChild { + s += ", right = [" + right.debugDescription + "]" + } + s += ", color = \(color)" + } + return s + } } extension RedBlackTree: CustomDebugStringConvertible { - public var debugDescription: String { - return root.debugDescription - } + public var debugDescription: String { + return root.debugDescription + } } extension RBTreeNode: CustomStringConvertible { - public var description: String { - var s = "" - if isNullLeaf { - s += "nullLeaf" - } else { - if let left = leftChild { - s += "(\(left.description)) <- " - } - if let key = key { - s += "\(key)" - } else { - s += "nil" - } - s += ", \(color)" - if let right = rightChild { - s += " -> (\(right.description))" - } - } - return s - } + public var description: String { + var s = "" + if isNullLeaf { + s += "nullLeaf" + } else { + if let left = leftChild { + s += "(\(left.description)) <- " + } + if let key = key { + s += "\(key)" + } else { + s += "nil" + } + s += ", \(color)" + if let right = rightChild { + s += " -> (\(right.description))" + } + } + return s + } } extension RedBlackTree: CustomStringConvertible { - public var description: String { - if root.isNullLeaf { - return "[]" - } else { - return root.description + public var description: String { + if root.isNullLeaf { + return "[]" + } else { + return root.description + } } - } } diff --git a/Red-Black Tree/RedBlackTree.swift b/Red-Black Tree/RedBlackTree.swift new file mode 100644 index 000000000..fc0411b42 --- /dev/null +++ b/Red-Black Tree/RedBlackTree.swift @@ -0,0 +1,795 @@ +//Copyright (c) 2016 Matthijs Hollemans and contributors +// +//Permission is hereby granted, free of charge, to any person obtaining a copy +//of this software and associated documentation files (the "Software"), to deal +//in the Software without restriction, including without limitation the rights +//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +//copies of the Software, and to permit persons to whom the Software is +//furnished to do so, subject to the following conditions: +// +//The above copyright notice and this permission notice shall be included in +//all copies or substantial portions of the Software. +// +//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +//OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +//THE SOFTWARE. + +import Foundation + +private enum RBTreeColor { + case red + case black +} + +private enum RotationDirection { + case left + case right +} + +// MARK: - RBNode + +public class RBTreeNode: Equatable { + public typealias RBNode = RBTreeNode + + fileprivate var color: RBTreeColor = .black + fileprivate var key: T? + var leftChild: RBNode? + var rightChild: RBNode? + fileprivate weak var parent: RBNode? + + public init(key: T?, leftChild: RBNode?, rightChild: RBNode?, parent: RBNode?) { + self.key = key + self.leftChild = leftChild + self.rightChild = rightChild + self.parent = parent + + self.leftChild?.parent = self + self.rightChild?.parent = self + } + + public convenience init(key: T?) { + self.init(key: key, leftChild: RBNode(), rightChild: RBNode(), parent: RBNode()) + } + + // For initialising the nullLeaf + public convenience init() { + self.init(key: nil, leftChild: nil, rightChild: nil, parent: nil) + self.color = .black + } + + var isRoot: Bool { + return parent == nil + } + + var isLeaf: Bool { + return rightChild == nil && leftChild == nil + } + + var isNullLeaf: Bool { + return key == nil && isLeaf && color == .black + } + + var isLeftChild: Bool { + return parent?.leftChild === self + } + + var isRightChild: Bool { + return parent?.rightChild === self + } + + var grandparent: RBNode? { + return parent?.parent + } + + var sibling: RBNode? { + if isLeftChild { + return parent?.rightChild + } else { + return parent?.leftChild + } + } + + var uncle: RBNode? { + return parent?.sibling + } +} + +// MARK: - RedBlackTree + +public class RedBlackTree { + public typealias RBNode = RBTreeNode + + fileprivate(set) var root: RBNode + fileprivate(set) var size = 0 + fileprivate let nullLeaf = RBNode() + fileprivate let allowDuplicateNode: Bool + + public init(_ allowDuplicateNode: Bool = false) { + root = nullLeaf + self.allowDuplicateNode = allowDuplicateNode + } +} + +// MARK: - Size + +extension RedBlackTree { + public func count() -> Int { + return size + } + + public func isEmpty() -> Bool { + return size == 0 + } + + public func allElements() -> [T] { + var nodes: [T] = [] + + getAllElements(node: root, nodes: &nodes) + + return nodes + } + + private func getAllElements(node: RBTreeNode, nodes: inout [T]) { + guard !node.isNullLeaf else { + return + } + + if let left = node.leftChild { + getAllElements(node: left, nodes: &nodes) + } + + if let key = node.key { + nodes.append(key) + } + + if let right = node.rightChild { + getAllElements(node: right, nodes: &nodes) + } + } +} + +// MARK: - Equatable protocol + +extension RBTreeNode { + static public func == (lhs: RBTreeNode, rhs: RBTreeNode) -> Bool { + return lhs.key == rhs.key + } +} + +// MARK: - Finding a nodes successor + +extension RBTreeNode { + /* + * Returns the inorder successor node of a node + * The successor is a node with the next larger key value of the current node + */ + public func getSuccessor() -> RBNode? { + // If node has right child: successor min of this right tree + if let rightChild = self.rightChild { + if !rightChild.isNullLeaf { + return rightChild.minimum() + } + } + // Else go upward until node left child + var currentNode = self + var parent = currentNode.parent + while currentNode.isRightChild { + if let parent = parent { + currentNode = parent + } + parent = currentNode.parent + } + return parent + } +} + +// MARK: - Searching + +extension RBTreeNode { + /* + * Returns the node with the minimum key of the current subtree + */ + public func minimum() -> RBNode? { + if let leftChild = leftChild { + if !leftChild.isNullLeaf { + return leftChild.minimum() + } + return self + } + return self + } + + /* + * Returns the node with the maximum key of the current subtree + */ + public func maximum() -> RBNode? { + if let rightChild = rightChild { + if !rightChild.isNullLeaf { + return rightChild.maximum() + } + return self + } + return self + } +} + +extension RedBlackTree { + /* + * Returns the node with the given key |input| if existing + */ + public func search(input: T) -> RBNode? { + return search(key: input, node: root) + } + + /* + * Returns the node with given |key| in subtree of |node| + */ + fileprivate func search(key: T, node: RBNode?) -> RBNode? { + // If node nil -> key not found + guard let node = node else { + return nil + } + // If node is nullLeaf == semantically same as if nil + if !node.isNullLeaf { + if let nodeKey = node.key { + // Node found + if key == nodeKey { + return node + } else if key < nodeKey { + return search(key: key, node: node.leftChild) + } else { + return search(key: key, node: node.rightChild) + } + } + } + return nil + } +} + +// MARK: - Finding maximum and minimum value + +extension RedBlackTree { + /* + * Returns the minimum key value of the whole tree + */ + public func minValue() -> T? { + guard let minNode = root.minimum() else { + return nil + } + return minNode.key + } + + /* + * Returns the maximum key value of the whole tree + */ + public func maxValue() -> T? { + guard let maxNode = root.maximum() else { + return nil + } + return maxNode.key + } +} + +// MARK: - Inserting new nodes + +extension RedBlackTree { + /* + * Insert a node with key |key| into the tree + * 1. Perform normal insert operation as in a binary search tree + * 2. Fix red-black properties + * Runntime: O(log n) + */ + public func insert(key: T) { + // If key must be unique and find the key already existed, quit + if search(input: key) != nil && !allowDuplicateNode { + return + } + + if root.isNullLeaf { + root = RBNode(key: key) + } else { + insert(input: RBNode(key: key), node: root) + } + + size += 1 + } + + /* + * Nearly identical insert operation as in a binary search tree + * Differences: All nil pointers are replaced by the nullLeaf, we color the inserted node red, + * after inserting we call insertFixup to maintain the red-black properties + */ + private func insert(input: RBNode, node: RBNode) { + guard let inputKey = input.key, let nodeKey = node.key else { + return + } + if inputKey < nodeKey { + guard let child = node.leftChild else { + addAsLeftChild(child: input, parent: node) + return + } + if child.isNullLeaf { + addAsLeftChild(child: input, parent: node) + } else { + insert(input: input, node: child) + } + } else { + guard let child = node.rightChild else { + addAsRightChild(child: input, parent: node) + return + } + if child.isNullLeaf { + addAsRightChild(child: input, parent: node) + } else { + insert(input: input, node: child) + } + } + } + + private func addAsLeftChild(child: RBNode, parent: RBNode) { + parent.leftChild = child + child.parent = parent + child.color = .red + insertFixup(node: child) + } + + private func addAsRightChild(child: RBNode, parent: RBNode) { + parent.rightChild = child + child.parent = parent + child.color = .red + insertFixup(node: child) + } + + /* + * Fixes possible violations of the red-black property after insertion + * Only violation of red-black properties occurs at inserted node |z| and z.parent + * We have 3 distinct cases: case 1, 2a and 2b + * - case 1: may repeat, but only h/2 steps, where h is the height of the tree + * - case 2a -> case 2b -> red-black tree + * - case 2b -> red-black tree + */ + private func insertFixup(node z: RBNode) { + if !z.isNullLeaf { + guard let parentZ = z.parent else { + return + } + // If both |z| and his parent are red -> violation of red-black property -> need to fix it + if parentZ.color == .red { + guard let uncle = z.uncle else { + return + } + // Case 1: Uncle red -> recolor + move z + if uncle.color == .red { + parentZ.color = .black + uncle.color = .black + if let grandparentZ = parentZ.parent { + grandparentZ.color = .red + // Move z to grandparent and check again + insertFixup(node: grandparentZ) + } + } + // Case 2: Uncle black + else { + var zNew = z + // Case 2.a: z right child -> rotate + if parentZ.isLeftChild && z.isRightChild { + zNew = parentZ + leftRotate(node: zNew) + } else if parentZ.isRightChild && z.isLeftChild { + zNew = parentZ + rightRotate(node: zNew) + } + // Case 2.b: z left child -> recolor + rotate + zNew.parent?.color = .black + if let grandparentZnew = zNew.grandparent { + grandparentZnew.color = .red + if z.isLeftChild { + rightRotate(node: grandparentZnew) + } else { + leftRotate(node: grandparentZnew) + } + // We have a valid red-black-tree + } + } + } + } + root.color = .black + } +} + +// MARK: - Deleting a node +extension RedBlackTree { + /* + * Delete a node with key |key| from the tree + * 1. Perform standard delete operation as in a binary search tree + * 2. Fix red-black properties + * Runntime: O(log n) + */ + public func delete(key: T) { + if size == 1 { + root = nullLeaf + size -= 1 + } else if let node = search(key: key, node: root) { + if !node.isNullLeaf { + delete(node: node) + size -= 1 + } + } + } + + /* + * Nearly identical delete operation as in a binary search tree + * Differences: All nil pointers are replaced by the nullLeaf, + * after deleting we call insertFixup to maintain the red-black properties if the delted node was + * black (as if it was red -> no violation of red-black properties) + */ + private func delete(node z: RBNode) { + var nodeY = RBNode() + var nodeX = RBNode() + if let leftChild = z.leftChild, let rightChild = z.rightChild { + if leftChild.isNullLeaf || rightChild.isNullLeaf { + nodeY = z + } else { + if let successor = z.getSuccessor() { + nodeY = successor + } + } + } + if let leftChild = nodeY.leftChild { + if !leftChild.isNullLeaf { + nodeX = leftChild + } else if let rightChild = nodeY.rightChild { + nodeX = rightChild + } + } + nodeX.parent = nodeY.parent + if let parentY = nodeY.parent { + // Should never be the case, as parent of root = nil + if parentY.isNullLeaf { + root = nodeX + } else { + if nodeY.isLeftChild { + parentY.leftChild = nodeX + } else { + parentY.rightChild = nodeX + } + } + } else { + root = nodeX + } + if nodeY != z { + z.key = nodeY.key + } + // If sliced out node was red -> nothing to do as red-black-property holds + // If it was black -> fix red-black-property + if nodeY.color == .black { + deleteFixup(node: nodeX) + } + } + + /* + * Fixes possible violations of the red-black property after deletion + * We have w distinct cases: only case 2 may repeat, but only h many steps, where h is the height + * of the tree + * - case 1 -> case 2 -> red-black tree + * case 1 -> case 3 -> case 4 -> red-black tree + * case 1 -> case 4 -> red-black tree + * - case 3 -> case 4 -> red-black tree + * - case 4 -> red-black tree + */ + private func deleteFixup(node x: RBNode) { + var xTmp = x + if !x.isRoot && x.color == .black { + guard var sibling = x.sibling else { + return + } + // Case 1: Sibling of x is red + if sibling.color == .red { + // Recolor + sibling.color = .black + if let parentX = x.parent { + parentX.color = .red + // Rotation + if x.isLeftChild { + leftRotate(node: parentX) + } else { + rightRotate(node: parentX) + } + // Update sibling + if let sibl = x.sibling { + sibling = sibl + } + } + } + // Case 2: Sibling is black with two black children + if sibling.leftChild?.color == .black && sibling.rightChild?.color == .black { + // Recolor + sibling.color = .red + // Move fake black unit upwards + if let parentX = x.parent { + deleteFixup(node: parentX) + } + // We have a valid red-black-tree + } else { + // Case 3: a. Sibling black with one black child to the right + if x.isLeftChild && sibling.rightChild?.color == .black { + // Recolor + sibling.leftChild?.color = .black + sibling.color = .red + // Rotate + rightRotate(node: sibling) + // Update sibling of x + if let sibl = x.sibling { + sibling = sibl + } + } + // Still case 3: b. One black child to the left + else if x.isRightChild && sibling.leftChild?.color == .black { + // Recolor + sibling.rightChild?.color = .black + sibling.color = .red + // Rotate + leftRotate(node: sibling) + // Update sibling of x + if let sibl = x.sibling { + sibling = sibl + } + } + // Case 4: Sibling is black with red right child + // Recolor + if let parentX = x.parent { + sibling.color = parentX.color + parentX.color = .black + // a. x left and sibling with red right child + if x.isLeftChild { + sibling.rightChild?.color = .black + // Rotate + leftRotate(node: parentX) + } + // b. x right and sibling with red left child + else { + sibling.leftChild?.color = .black + //Rotate + rightRotate(node: parentX) + } + // We have a valid red-black-tree + xTmp = root + } + } + } + xTmp.color = .black + } +} + +// MARK: - Rotation +extension RedBlackTree { + /* + * Left rotation around node x + * Assumes that x.rightChild y is not a nullLeaf, rotates around the link from x to y, + * makes y the new root of the subtree with x as y's left child and y's left child as x's right + * child, where n = a node, [n] = a subtree + * | | + * x y + * / \ ~> / \ + * [A] y x [C] + * / \ / \ + * [B] [C] [A] [B] + */ + fileprivate func leftRotate(node x: RBNode) { + rotate(node: x, direction: .left) + } + + /* + * Right rotation around node y + * Assumes that y.leftChild x is not a nullLeaf, rotates around the link from y to x, + * makes x the new root of the subtree with y as x's right child and x's right child as y's left + * child, where n = a node, [n] = a subtree + * | | + * x y + * / \ <~ / \ + * [A] y x [C] + * / \ / \ + * [B] [C] [A] [B] + */ + fileprivate func rightRotate(node x: RBNode) { + rotate(node: x, direction: .right) + } + + /* + * Rotation around a node x + * Is a local operation preserving the binary-search-tree property that only exchanges pointers. + * Runntime: O(1) + */ + private func rotate(node x: RBNode, direction: RotationDirection) { + var nodeY: RBNode? = RBNode() + + // Set |nodeY| and turn |nodeY|'s left/right subtree into |x|'s right/left subtree + switch direction { + case .left: + nodeY = x.rightChild + x.rightChild = nodeY?.leftChild + x.rightChild?.parent = x + case .right: + nodeY = x.leftChild + x.leftChild = nodeY?.rightChild + x.leftChild?.parent = x + } + + // Link |x|'s parent to nodeY + nodeY?.parent = x.parent + if x.isRoot { + if let node = nodeY { + root = node + } + } else if x.isLeftChild { + x.parent?.leftChild = nodeY + } else if x.isRightChild { + x.parent?.rightChild = nodeY + } + + // Put |x| on |nodeY|'s left + switch direction { + case .left: + nodeY?.leftChild = x + case .right: + nodeY?.rightChild = x + } + x.parent = nodeY + } +} + +// MARK: - Verify +extension RedBlackTree { + /* + * Verifies that the existing tree fulfills all red-black properties + * Returns true if the tree is a valid red-black tree, false otherwise + */ + public func verify() -> Bool { + if root.isNullLeaf { + print("The tree is empty") + return true + } + return property2() && property4() && property5() + } + + // Property 1: Every node is either red or black -> fullfilled through setting node.color of type + // RBTreeColor + + // Property 2: The root is black + private func property2() -> Bool { + if root.color == .red { + print("Property-Error: Root is red") + return false + } + return true + } + + // Property 3: Every nullLeaf is black -> fullfilled through initialising nullLeafs with color = black + + // Property 4: If a node is red, then both its children are black + private func property4() -> Bool { + return property4(node: root) + } + + private func property4(node: RBNode) -> Bool { + if node.isNullLeaf { + return true + } + if let leftChild = node.leftChild, let rightChild = node.rightChild { + if node.color == .red { + if !leftChild.isNullLeaf && leftChild.color == .red { + print("Property-Error: Red node with key \(String(describing: node.key)) has red left child") + return false + } + if !rightChild.isNullLeaf && rightChild.color == .red { + print("Property-Error: Red node with key \(String(describing: node.key)) has red right child") + return false + } + } + return property4(node: leftChild) && property4(node: rightChild) + } + return false + } + + // Property 5: For each node, all paths from the node to descendant leaves contain the same number + // of black nodes (same blackheight) + private func property5() -> Bool { + if property5(node: root) == -1 { + return false + } else { + return true + } + } + + private func property5(node: RBNode) -> Int { + if node.isNullLeaf { + return 0 + } + guard let leftChild = node.leftChild, let rightChild = node.rightChild else { + return -1 + } + let left = property5(node: leftChild) + let right = property5(node: rightChild) + + if left == -1 || right == -1 { + return -1 + } else if left == right { + let addedHeight = node.color == .black ? 1 : 0 + return left + addedHeight + } else { + print("Property-Error: Black height violated at node with key \(String(describing: node.key))") + return -1 + } + } +} + +// MARK: - Debugging + +extension RBTreeNode: CustomDebugStringConvertible { + public var debugDescription: String { + var s = "" + if isNullLeaf { + s = "nullLeaf" + } else { + if let key = key { + s = "key: \(key)" + } else { + s = "key: nil" + } + if let parent = parent { + s += ", parent: \(String(describing: parent.key))" + } + if let left = leftChild { + s += ", left = [" + left.debugDescription + "]" + } + if let right = rightChild { + s += ", right = [" + right.debugDescription + "]" + } + s += ", color = \(color)" + } + return s + } +} + +extension RedBlackTree: CustomDebugStringConvertible { + public var debugDescription: String { + return root.debugDescription + } +} + +extension RBTreeNode: CustomStringConvertible { + public var description: String { + var s = "" + if isNullLeaf { + s += "nullLeaf" + } else { + if let left = leftChild { + s += "(\(left.description)) <- " + } + if let key = key { + s += "\(key)" + } else { + s += "nil" + } + s += ", \(color)" + if let right = rightChild { + s += " -> (\(right.description))" + } + } + return s + } +} + +extension RedBlackTree: CustomStringConvertible { + public var description: String { + if root.isNullLeaf { + return "[]" + } else { + return root.description + } + } +} From 7cb8185679cdc3acf38e9123ef7503fba5b4d116 Mon Sep 17 00:00:00 2001 From: Alejandro Isaza Date: Sat, 7 Oct 2017 15:50:19 -0700 Subject: [PATCH 005/271] Add A* algorithm --- A-Star/AStar.swift | 153 +++++++++ A-Star/README.md | 7 + A-Star/Tests/AStarTests.swift | 57 ++++ .../AStarTests.xcodeproj/project.pbxproj | 291 ++++++++++++++++++ .../contents.xcworkspacedata | 7 + A-Star/Tests/Info.plist | 24 ++ Hashed Heap/HashedHeap.swift | 13 +- .../contents.xcworkspacedata | 23 ++ 8 files changed, 574 insertions(+), 1 deletion(-) create mode 100644 A-Star/AStar.swift create mode 100644 A-Star/README.md create mode 100755 A-Star/Tests/AStarTests.swift create mode 100644 A-Star/Tests/AStarTests.xcodeproj/project.pbxproj create mode 100644 A-Star/Tests/AStarTests.xcodeproj/project.xcworkspace/contents.xcworkspacedata create mode 100644 A-Star/Tests/Info.plist diff --git a/A-Star/AStar.swift b/A-Star/AStar.swift new file mode 100644 index 000000000..41a9fac6c --- /dev/null +++ b/A-Star/AStar.swift @@ -0,0 +1,153 @@ +// Written by Alejandro Isaza. + +import Foundation + +public protocol Graph { + associatedtype Vertex: Hashable + associatedtype Edge: WeightedEdge where Edge.Vertex == Vertex + + /// Lists all edges going out from a vertex. + func edgesOutgoing(from vertex: Vertex) -> [Edge] +} + +public protocol WeightedEdge { + associatedtype Vertex + + /// The edge's cost. + var cost: Double { get } + + /// The target vertex. + var target: Vertex { get } +} + +public final class AStar { + /// The graph to search on. + public let graph: G + + /// The heuristic cost function that estimates the cost between two vertices. + /// + /// - Note: The heuristic function needs to always return a value that is lower-than or equal to the actual + /// cost for the resulting path of the A* search to be optimal. + public let heuristic: (G.Vertex, G.Vertex) -> Double + + /// Open list of nodes to expand. + private var open: HashedHeap> + + /// Closed list of vertices already expanded. + private var closed = Set() + + /// Actual vertex cost for vertices we already encountered (refered to as `g` on the literature). + private var costs = Dictionary() + + /// Store the previous node for each expanded node to recreate the path. + private var parents = Dictionary() + + /// Initializes `AStar` with a graph and a heuristic cost function. + public init(graph: G, heuristic: @escaping (G.Vertex, G.Vertex) -> Double) { + self.graph = graph + self.heuristic = heuristic + open = HashedHeap(sort: <) + } + + /// Finds an optimal path between `source` and `target`. + /// + /// - Precondition: both `source` and `target` belong to `graph`. + public func path(start: G.Vertex, target: G.Vertex) -> [G.Vertex] { + open.insert(Node(vertex: start, cost: 0, estimate: heuristic(start, target))) + while !open.isEmpty { + guard let node = open.remove() else { + break + } + costs[node.vertex] = node.cost + + if (node.vertex == target) { + let path = buildPath(start: start, target: target) + cleanup() + return path + } + + if !closed.contains(node.vertex) { + expand(node: node, target: target) + closed.insert(node.vertex) + } + } + + // No path found + return [] + } + + private func expand(node: Node, target: G.Vertex) { + let edges = graph.edgesOutgoing(from: node.vertex) + for edge in edges { + let g = cost(node.vertex) + edge.cost + if g < cost(edge.target) { + open.insert(Node(vertex: edge.target, cost: g, estimate: heuristic(edge.target, target))) + parents[edge.target] = node.vertex + } + } + } + + private func cost(_ vertex: G.Edge.Vertex) -> Double { + if let c = costs[vertex] { + return c + } + + let node = Node(vertex: vertex, cost: Double.greatestFiniteMagnitude, estimate: 0) + if let index = open.index(of: node) { + return open[index].cost + } + + return Double.greatestFiniteMagnitude + } + + private func buildPath(start: G.Vertex, target: G.Vertex) -> [G.Vertex] { + var path = Array() + path.append(target) + + var current = target + while current != start { + guard let parent = parents[current] else { + return [] // no path found + } + current = parent + path.append(current) + } + + return path.reversed() + } + + private func cleanup() { + open.removeAll() + closed.removeAll() + parents.removeAll() + } +} + +private struct Node: Hashable, Comparable { + /// The graph vertex. + var vertex: V + + /// The actual cost between the start vertex and this vertex. + var cost: Double + + /// Estimated (heuristic) cost betweent this vertex and the target vertex. + var estimate: Double + + public init(vertex: V, cost: Double, estimate: Double) { + self.vertex = vertex + self.cost = cost + self.estimate = estimate + } + + static func < (lhs: Node, rhs: Node) -> Bool { + return lhs.cost + lhs.estimate < rhs.cost + rhs.estimate + } + + static func == (lhs: Node, rhs: Node) -> Bool { + return lhs.vertex == rhs.vertex + } + + var hashValue: Int { + return vertex.hashValue + } +} diff --git a/A-Star/README.md b/A-Star/README.md new file mode 100644 index 000000000..cafd5027a --- /dev/null +++ b/A-Star/README.md @@ -0,0 +1,7 @@ +# A* + +A* (pronounced "ay star") is a heuristic best-first search algorithm. A* minimizes node expansions, therefore minimizing the search time, by using a heuristic function. The heuristic function gives an estimate of the distance between two vertices. For instance if you are searching for a path between two points in a city, you can estimate the actual street distance with the straight-line distance. + +A* works by expanding the most promising nodes first, according to the heuristic function. In the city example it would choose streets which go in the general direction of the target first and, only if those are dead ends, backtrack and try other streets. This speeds up search in most sitations. + +A* is optimal (it always find the shortest path) if the heuristic function is admissible. A heuristic function is admissible if it never overestimates the cost of reaching the goal. In the extreme case of the heuristic function always retuning `0` A* acts exactly the same as [Dijkstra's Algorithm](../Dijkstra). The closer the heuristic function is the the actual distance the faster the search. diff --git a/A-Star/Tests/AStarTests.swift b/A-Star/Tests/AStarTests.swift new file mode 100755 index 000000000..87f674cd5 --- /dev/null +++ b/A-Star/Tests/AStarTests.swift @@ -0,0 +1,57 @@ +import Foundation +import XCTest + +struct GridGraph: Graph { + struct Vertex: Hashable { + var x: Int + var y: Int + + static func == (lhs: Vertex, rhs: Vertex) -> Bool { + return lhs.x == rhs.x && lhs.y == rhs.y + } + + public var hashValue: Int { + return x.hashValue ^ y.hashValue + } + } + + struct Edge: WeightedEdge { + var cost: Double + var target: Vertex + } + + func edgesOutgoing(from vertex: Vertex) -> [Edge] { + return [ + Edge(cost: 1, target: Vertex(x: vertex.x - 1, y: vertex.y)), + Edge(cost: 1, target: Vertex(x: vertex.x + 1, y: vertex.y)), + Edge(cost: 1, target: Vertex(x: vertex.x, y: vertex.y - 1)), + Edge(cost: 1, target: Vertex(x: vertex.x, y: vertex.y + 1)), + ] + } +} + +class AStarTests: XCTestCase { + func testSameStartAndEnd() { + let graph = GridGraph() + let astar = AStar(graph: graph, heuristic: manhattanDistance) + let path = astar.path(start: GridGraph.Vertex(x: 0, y: 0), target: GridGraph.Vertex(x: 0, y: 0)) + XCTAssertEqual(path.count, 1) + XCTAssertEqual(path[0].x, 0) + XCTAssertEqual(path[0].y, 0) + } + + func testDiagonal() { + let graph = GridGraph() + let astar = AStar(graph: graph, heuristic: manhattanDistance) + let path = astar.path(start: GridGraph.Vertex(x: 0, y: 0), target: GridGraph.Vertex(x: 10, y: 10)) + XCTAssertEqual(path.count, 21) + XCTAssertEqual(path[0].x, 0) + XCTAssertEqual(path[0].y, 0) + XCTAssertEqual(path[20].x, 10) + XCTAssertEqual(path[20].y, 10) + } + + func manhattanDistance(_ s: GridGraph.Vertex, _ t: GridGraph.Vertex) -> Double { + return Double(abs(s.x - t.x) + abs(s.y - t.y)) + } +} diff --git a/A-Star/Tests/AStarTests.xcodeproj/project.pbxproj b/A-Star/Tests/AStarTests.xcodeproj/project.pbxproj new file mode 100644 index 000000000..cacd1e5ae --- /dev/null +++ b/A-Star/Tests/AStarTests.xcodeproj/project.pbxproj @@ -0,0 +1,291 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 611D099C1F8978AB00C7092B /* AStarTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 611D099B1F8978AB00C7092B /* AStarTests.swift */; }; + 611D099E1F8978BC00C7092B /* AStar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 611D099D1F8978BB00C7092B /* AStar.swift */; }; + 611D09A01F89795100C7092B /* HashedHeap.swift in Sources */ = {isa = PBXBuildFile; fileRef = 611D099F1F89795100C7092B /* HashedHeap.swift */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 611D099B1F8978AB00C7092B /* AStarTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AStarTests.swift; sourceTree = ""; }; + 611D099D1F8978BB00C7092B /* AStar.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = AStar.swift; path = ../AStar.swift; sourceTree = ""; }; + 611D099F1F89795100C7092B /* HashedHeap.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = HashedHeap.swift; path = "../../Hashed Heap/HashedHeap.swift"; sourceTree = ""; }; + 7B2BBC801C779D720067B71D /* AStarTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = AStarTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 7B2BBC941C779E7B0067B71D /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = SOURCE_ROOT; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 7B2BBC7D1C779D720067B71D /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 7B2BBC681C779D710067B71D = { + isa = PBXGroup; + children = ( + 7B2BBC831C779D720067B71D /* Tests */, + 7B2BBC721C779D710067B71D /* Products */, + ); + sourceTree = ""; + }; + 7B2BBC721C779D710067B71D /* Products */ = { + isa = PBXGroup; + children = ( + 7B2BBC801C779D720067B71D /* AStarTests.xctest */, + ); + name = Products; + sourceTree = ""; + }; + 7B2BBC831C779D720067B71D /* Tests */ = { + isa = PBXGroup; + children = ( + 611D099F1F89795100C7092B /* HashedHeap.swift */, + 611D099D1F8978BB00C7092B /* AStar.swift */, + 611D099B1F8978AB00C7092B /* AStarTests.swift */, + 7B2BBC941C779E7B0067B71D /* Info.plist */, + ); + name = Tests; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 7B2BBC7F1C779D720067B71D /* AStarTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 7B2BBC8C1C779D720067B71D /* Build configuration list for PBXNativeTarget "AStarTests" */; + buildPhases = ( + 7B2BBC7C1C779D720067B71D /* Sources */, + 7B2BBC7D1C779D720067B71D /* Frameworks */, + 7B2BBC7E1C779D720067B71D /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = AStarTests; + productName = TestsTests; + productReference = 7B2BBC801C779D720067B71D /* AStarTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 7B2BBC691C779D710067B71D /* Project object */ = { + isa = PBXProject; + attributes = { + LastSwiftUpdateCheck = 0720; + LastUpgradeCheck = 0900; + ORGANIZATIONNAME = "Swift Algorithm Club"; + TargetAttributes = { + 7B2BBC7F1C779D720067B71D = { + CreatedOnToolsVersion = 7.2; + LastSwiftMigration = 0900; + }; + }; + }; + buildConfigurationList = 7B2BBC6C1C779D710067B71D /* Build configuration list for PBXProject "AStarTests" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 7B2BBC681C779D710067B71D; + productRefGroup = 7B2BBC721C779D710067B71D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 7B2BBC7F1C779D720067B71D /* AStarTests */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 7B2BBC7E1C779D720067B71D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 7B2BBC7C1C779D720067B71D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 611D099C1F8978AB00C7092B /* AStarTests.swift in Sources */, + 611D099E1F8978BC00C7092B /* AStar.swift in Sources */, + 611D09A01F89795100C7092B /* HashedHeap.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + 7B2BBC871C779D720067B71D /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.11; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = macosx; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_SWIFT3_OBJC_INFERENCE = Default; + }; + name = Debug; + }; + 7B2BBC881C779D720067B71D /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.11; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = macosx; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + SWIFT_SWIFT3_OBJC_INFERENCE = Default; + }; + name = Release; + }; + 7B2BBC8D1C779D720067B71D /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_ENABLE_MODULES = YES; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = swift.algorithm.club.Tests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_SWIFT3_OBJC_INFERENCE = Default; + SWIFT_VERSION = 4.0; + }; + name = Debug; + }; + 7B2BBC8E1C779D720067B71D /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_ENABLE_MODULES = YES; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = swift.algorithm.club.Tests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_SWIFT3_OBJC_INFERENCE = Default; + SWIFT_VERSION = 4.0; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 7B2BBC6C1C779D710067B71D /* Build configuration list for PBXProject "AStarTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 7B2BBC871C779D720067B71D /* Debug */, + 7B2BBC881C779D720067B71D /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 7B2BBC8C1C779D720067B71D /* Build configuration list for PBXNativeTarget "AStarTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 7B2BBC8D1C779D720067B71D /* Debug */, + 7B2BBC8E1C779D720067B71D /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 7B2BBC691C779D710067B71D /* Project object */; +} diff --git a/A-Star/Tests/AStarTests.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/A-Star/Tests/AStarTests.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..6c0ea8493 --- /dev/null +++ b/A-Star/Tests/AStarTests.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/A-Star/Tests/Info.plist b/A-Star/Tests/Info.plist new file mode 100644 index 000000000..ba72822e8 --- /dev/null +++ b/A-Star/Tests/Info.plist @@ -0,0 +1,24 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + BNDL + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1 + + diff --git a/Hashed Heap/HashedHeap.swift b/Hashed Heap/HashedHeap.swift index be7d9ab78..106cdacb0 100644 --- a/Hashed Heap/HashedHeap.swift +++ b/Hashed Heap/HashedHeap.swift @@ -57,7 +57,12 @@ public struct HashedHeap { public var count: Int { return elements.count } - + + /// Accesses an element by its index. + public subscript(index: Int) -> T { + return elements[index] + } + /// Returns the index of the given element. /// /// This is the operation that a hashed heap optimizes in compassion with a normal heap. In a normal heap this @@ -141,6 +146,12 @@ public struct HashedHeap { } return removeLast() } + + /// Removes all elements from the heap. + public mutating func removeAll() { + elements.removeAll() + indices.removeAll() + } /// Removes the last element from the heap. /// diff --git a/swift-algorithm-club.xcworkspace/contents.xcworkspacedata b/swift-algorithm-club.xcworkspace/contents.xcworkspacedata index 4cab8e2d4..28fb4f1a7 100644 --- a/swift-algorithm-club.xcworkspace/contents.xcworkspacedata +++ b/swift-algorithm-club.xcworkspace/contents.xcworkspacedata @@ -38,6 +38,29 @@ + + + + + + + + + + + + + + From cb26964f1ea032be9fbe7b64f1f6e849d1fda5d5 Mon Sep 17 00:00:00 2001 From: Alejandro Isaza Date: Sat, 7 Oct 2017 15:53:59 -0700 Subject: [PATCH 006/271] Add to .travis.yml --- .travis.yml | 1 + .../xcschemes/AStarTests.xcscheme | 67 +++++++++++++++++++ 2 files changed, 68 insertions(+) create mode 100644 A-Star/Tests/AStarTests.xcodeproj/xcshareddata/xcschemes/AStarTests.xcscheme diff --git a/.travis.yml b/.travis.yml index 7cd02c9bc..30b54f140 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,6 +9,7 @@ install: script: +- xcodebuild test -project ./A-Star/Tests/AStarTests.xcodeproj -scheme AStarTests | xcpretty -f `xcpretty-travis-formatter` - xcodebuild test -project ./Array2D/Tests/Tests.xcodeproj -scheme Tests | xcpretty -f `xcpretty-travis-formatter` - xcodebuild test -project ./All-Pairs\ Shortest\ Paths/APSP/APSP.xcodeproj -scheme APSPTests | xcpretty -f `xcpretty-travis-formatter` - xcodebuild test -project ./AVL\ Tree/Tests/Tests.xcodeproj -scheme Tests | xcpretty -f `xcpretty-travis-formatter` diff --git a/A-Star/Tests/AStarTests.xcodeproj/xcshareddata/xcschemes/AStarTests.xcscheme b/A-Star/Tests/AStarTests.xcodeproj/xcshareddata/xcschemes/AStarTests.xcscheme new file mode 100644 index 000000000..5473b4c0c --- /dev/null +++ b/A-Star/Tests/AStarTests.xcodeproj/xcshareddata/xcschemes/AStarTests.xcscheme @@ -0,0 +1,67 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 2c2ec49e225861e9aa0da42b54e35c90f81ddbed Mon Sep 17 00:00:00 2001 From: Alejandro Isaza Date: Thu, 16 Nov 2017 22:17:19 -0800 Subject: [PATCH 007/271] Add example to README --- A-Star/Images/graph.dot | 12 ++++++++++++ A-Star/Images/graph.png | Bin 0 -> 20882 bytes A-Star/Images/step1.dot | 12 ++++++++++++ A-Star/Images/step1.png | Bin 0 -> 28753 bytes A-Star/Images/step2.dot | 12 ++++++++++++ A-Star/Images/step2.png | Bin 0 -> 29088 bytes A-Star/Images/step3.dot | 12 ++++++++++++ A-Star/Images/step3.png | Bin 0 -> 30158 bytes A-Star/Images/step4.dot | 12 ++++++++++++ A-Star/Images/step4.png | Bin 0 -> 30130 bytes A-Star/Images/step5.dot | 12 ++++++++++++ A-Star/Images/step5.png | Bin 0 -> 29802 bytes A-Star/Images/step6.dot | 12 ++++++++++++ A-Star/Images/step6.png | Bin 0 -> 29596 bytes A-Star/Images/step7.dot | 12 ++++++++++++ A-Star/Images/step7.png | Bin 0 -> 30012 bytes A-Star/README.md | 38 +++++++++++++++++++++++++++++++++++++- 17 files changed, 133 insertions(+), 1 deletion(-) create mode 100644 A-Star/Images/graph.dot create mode 100644 A-Star/Images/graph.png create mode 100644 A-Star/Images/step1.dot create mode 100644 A-Star/Images/step1.png create mode 100644 A-Star/Images/step2.dot create mode 100644 A-Star/Images/step2.png create mode 100644 A-Star/Images/step3.dot create mode 100644 A-Star/Images/step3.png create mode 100644 A-Star/Images/step4.dot create mode 100644 A-Star/Images/step4.png create mode 100644 A-Star/Images/step5.dot create mode 100644 A-Star/Images/step5.png create mode 100644 A-Star/Images/step6.dot create mode 100644 A-Star/Images/step6.png create mode 100644 A-Star/Images/step7.dot create mode 100644 A-Star/Images/step7.png diff --git a/A-Star/Images/graph.dot b/A-Star/Images/graph.dot new file mode 100644 index 000000000..941d66232 --- /dev/null +++ b/A-Star/Images/graph.dot @@ -0,0 +1,12 @@ +digraph G { + rankdir=LR; + { A [ label = "h = 3" ] } + { rank = same; B [ label = "h = 2" ]; C [ label = "h = 2" ]; D [ label = "h = 2" ] } + { rank = same; E [ label = "h = 1" ]; F [ label = "h = 1" ]; G [ label = "h = 1" ] } + { H [ label = "h = 0", style = filled, color = green ] } + A -> { B C D } + B -> E + E -> F + D -> G + G -> H +} diff --git a/A-Star/Images/graph.png b/A-Star/Images/graph.png new file mode 100644 index 0000000000000000000000000000000000000000..c0a4b1cc8fd31a372f6843f858703950a0adee4a GIT binary patch literal 20882 zcmZ7eWmFwa+cf~<4nY&#EfCxxxVyW%hTsHu4ek&uI0v`j?(XjH?mo@^KHr*I^Cu)( zO`oo=s;l<3<%B87i6bN6B7lK`Axlb#D1m{24+4K5hJykAg!Z)<1Ac%zDv1k$m5<>c zf`JKuNs0)n`~pAqf`3t+etNTxm?GA}qKQk;#zhiU3`J#@NAocm_&#n*X`6~b!k<@^ z#~d`Efb)AQTcS%fOgh+O^!WXI#oZxK`s0b?7~z_$*WJD6IG;zwrlv=QYnf|nH||*D zq>%|6Hbk&5i2?9q7F7dMW=fUEnhFVAxC50D3iu%~$BOj-{TDG8L?3zlwvjpV|GPk2 za*5^RcmKOZo{+(*3jczea5gra=k+KD^Ut;Kyr1c`$fc9%W%2o6E&^W8ect2sy&pxR z>*n>e=d^$F^3Lh|cs=&>zmXv0vCkOSjIzi7s9#mnsHKc39c_CPv0Kb*{v{Qh>|9`^S3dcU487Kt17R<7IpkJVy=cye9# z5BqGJnNQ7mB$A&Ji9t9|z7Tit?#pFA5wme0QYyDIi126IV}YF=`D~fCdK$;iOl+vZ zm!sJdDwAN72zY1N^>j!KSIw7;bt{FF=K^wauh zlj`k#HAq!$)EnMYQ*%AWL-o{b+#i)DkCSF2+6M-19LIF9qr?t8t51StJmuiS<@Rpl zerEi6`@5dHZ}VAG$;E>A^J%{6a8es16AB3N^S24rL!R@NTu4?}Gv@t&KbD6CVF~iY zn_W(&-~~&ENUzfv4gCqH3uG~9h8?@Q+9HCFm1Obm4HTO2?tON2> z0x$vky?@&<<3uTS?AtE;@R;qlMBJVZ3srl>t4<`TGRT3kv><0|8l)V?WqChIX8ziO zKRvHsbC+gcvLIXh+5Va!d0N#^SiKpHXExMTzux|GC7qE_)lMa!`K|r+?$2D%>!^9O z5)7GeHZhb1m8A*XP5>AT`Ta(~rzT*bP0Y=mR(7MDWqO?1uX{iL;9JDnB`jrJJuJ*R zBOY=_J!~|N=A9c&WhtaK73Ebv`P$?-#?^1AdO(csDo*58>v5Q$jIVa)XYmBg^a-$* zb}KnFrb$Re+$=$j(GTWDm$#8gm~N>0MTNcIcnN_~!7VN^|;HD8TXLNOi>n;`@}KHR={N3+ADnY_(2vv8(vCQ*gy4&mCatIn%?e}109Ami>-zGEN! z^SoO$Kim4v;GzKLpt0EW_WI0Y0}a(Qrq*acY9Pa$@`}EoWxorCEKI;S&i8Bs3!T<6 z$EMkvZGTu9vd8Uoura4)O*dbm-!4$*89&>ov(H)8@b+}9JDSF}nxt)eNG#{N086j# zd_{BLeBS0buj`s2g^tT+wL|E2qu6iWF@QSo8JOBdQmpG^&IN@Qu__u&BYaGDp-4E` zp%6m%0m0!ZL;2B2LSF8f)63>7g)V#G*2X`ZZ zUbnMDGIy)4`u9McXvSPssAe`BOD`t9=XO3i09BhnYYYAr?MN}PXf9{PYCkS-cIx=P z6C;eTav`m3fg|NdSsG9SK_JkWg(a@l=#YQB*4i9U2EyZZvM?dZ#(r$M9-D5pq#^B` zW3T>E7mO9<%QV=<6k&pbDeeIFH;MQ@e@mdU(ecMpt^FU{recr#RoCr_9TB|6J0D9ASkrbvX zvzVS19w%nw9PX60vNcY$$L}-o9F%9welBs~;9E3CX`Azy4-uqkcZA ziT-{&qYS~oOK}=)^jS=NQ$ZEEuQPEfcpYVMH zCn}O;g<7_8FU`7T`VPk!c=>$|*R2K0mI08EZ1|f&eLO$1N>B|d4PaadzyGRCcUiLh z+aH9cU6j{_g~1<5LuR-9qaGfg297LZ2H1U9(RXw%a0{5sF1mWHofrKyzdzH(Au_a7 zK1Fk7J|5&o2L_DLRHVCTs1nob#q99>=&M1lxw%)HDt0$R` zhMX?g_Y)wR#i-aCaaIpAw71xt8Y-AEd+>*0kOVKd@5G9~jLcmj&_WDGP@U?up!(`& zchgjFh#Bvd85UpA7qOi9vy6~Ha%)#;*OyzbG*mUEl z2&nb1Ha<<5-b4Wf!6LNghHmWTxWRr~C!SK4m04o1}_ugRx#!&uxU!8M5@iez*^( zEsv4se`TFNiPLKbPCLY9anVd-RH67mRdrnoV0P zze@K7S@d@$R3wectLw6mFtiLrs7Stt4aiQARO+w!a@|?wsrz-GtlBhSVJ6O%X(Ljh zc`I-|{kbh@Xh@MGv_Kb%wMKnjj`ptkUM&t3oI4HCD=GKHO@qqUyXEIKzR)`;zbNPE z7@FH&QmFZ|J&K_6J_&Co$h{!!grlI4ci1p$WZ!t(+q7;$0`Rz5$1y)x!XmwRn(}`O z>oy_lJ=`t8eH>2f=7)d-slfTNIYMbq{EL@KSI;o@8eA#C`JVPM8iFMI+ArhvQ7}$} zF2CB^AIoa3_rz(Tu z5ITPyjL<}Kz7U}EABN0ci-%LwPc^&#oLyM4EX?pM<9Rr867;nYEUJ*v+`Hi+3yh(b8~I1ig%#7?o2=`S z`tqA%hv&QJTmK?HNx7zIQ_#Kq7$GDbdy$JTFWycoTu;(y(0+KYK@{@<`vx%@~e z&NeBQ&uOu~BaQZ=svd?KE$g~0QtVR99N;q=_~QD-lRU^eB`C;54hbC%^L}R*KNEF1 zo|DBPlVt^k|IzgMmzypUxjh(9Ragdr^Bt>tNVF#wqZ~ty^RJF-r32*0aD1Ia8bN~3 z{NX5vpwjeM{=R4;hSZ)m;FPnJqLdUH7fihK#}YNECCJl=v)x6YFzT_B5+p4jpqAU^ zGsxoeVl`mJl2cLy5U(ndtoYq7I*#(R+sQ&zF{o&NvD|@qaIwZ5kxKW!)r%b;;rfo) zn_kQ1u^IHm(=aZRdiyjs z_NaF-g$RRr={`;)YQ5*)58=m}chmZ#wl|3o*pj;#llTUJ2Nm!2uvZX-{A~{pwoszm z12o24U#^DFuE+UZ#qsR}GrP0TvNyF9a0YE*;wN4-ZD%1%VomCIJW=j^Pzsn)ARWf; zKX1brWiSZ3Z-i?8Wwn~2h84?6nHI&bjVDM*!><*(#rFi~VH_9wE$PlbqK%I)X2GSw z)%<+kzHUewf3u_`FEn#h`QIFYg7ubuX|ok)F*8XCedkwXocKGn6)Co>KvBq ztP8h}!!W4I-#XuZ(?RSd(f`xcZ`@>^G8fnc4yo#^PfYJ(=ZviN4F@^DNjr%bGghcX z0x{igCdHvAWsTOl6aPe)!Op(rGZ>Hw`@$_qO=Si^K`a<6;R#r!5jsr>hF#mghLnVV z;E`PGi4b!DF_J+;x8f^KJME36DplyUO4QM1^(ip@URt|>Nf<+6%W65z{C|KkA#IwA zefE0YhNJ>sqlC&1$o&y7@wt<*&rxHK2c@iOYMS z3rC6@&9A3O8<|l3XcqLK{T@8?z36$-FXN{Y9D?4%KW%MV6*CRm-KtMoOE(V!{aCR@ zY)&61Oa_JV_w$x(m3X!zLiHx6!<^09qDv{N-H8o`Czj875ChmaN)blp?%+lSKY*@< z6lkDna}3{UA!ck%p+33u{)MBVXSy9ArZ(c;j$mPhp@hWg_rv}hB)43=D#MZ-eo2+P z;vL+%MQ%8j&efEL0vhh5z8Az^GLvCOYE=p5p0ag#x;Z>5Nq`L7AEeCKK4Mmxt|vWg z4Qi8v{X|&WreA|RxT_64l#Z54MkQ9!auuEyJQ2)1#Oi#ck^we_A6zBh$YE^)M=lH; zbId9y>7*T4(A~0iwyRoEd`}je2-g9h_(JiyO;Bvew!bOuxB&1`v^;W=)uMjYWjZCx z>AK%*0XX@o|11kRBQJ~nF=*P)?Lw#WUu?QTR243(ej`B@WDuIm`;ID*_v?NqUY;9j z$Qgim@?CY(^}| zEmu=28NKJ{z45H`SIi^%Cdoip0$622*hzCP~=ytf%tA z@L0@bsFxK_q=d;2H@x}`e=Z5;Y$P%0>z$DPj(cx$yVe0#?oDIgTgfvpnsB8kQ(Rf# zj1sHSkN=189EM`VO7N{gN}?B)mRVe{f7Vpg|FZFTsjg%X5-lU3VmO>1_RdG7)b929 zUcGR|B<4c(7`2SF@)lXB_hH0tb~alO(%FB#LZAPB(L4+KuNBU*Z$si)j4;Y1)}_nx zkNxbrj7!4i4%DJ>pss^LMP8n#<@qz5@-r;U4CL2G+1L7{>0j$7x-1_{4X!l#_U*I7lSe zei>Hlxo@s}spi}b?9-l&(QGCIsQ0~J^i7)TsN0qEUI5h29Ufo5;vh}%4UI)vT?DfZ zcQ+a=b?aaR!mD8)#rSsqTCTOs{b%tX zU1G7)U_ZNz@HXb#e#6iGV~O>z6+a~1bY4I#{XxK8igA?U>8w9uH4+U;rO6;V4wpmT z#5{w@AKVT+kCmnI6YD3zRf7Ozn$_+8FHO_AYM}XbVCP4<4<62y{V_OK#135YoP6@D z-4*^6uyBNp6!P9d}2*_1K`7>+gtAA zQZi4oh57Hq>{xd!*Sl2~lcc9V@3=5SS%1piEX>WP>+-55iA?%~sB8A$TZ=4WE|)MS*LY6w$L$M*bjK z#h{LRLp2vDg~oGQiHy{j zg?;-dxh=ArB-Kn{kRuokl`DOT%K*Ptk|R&eVqx+dV1F!c|6Wp^F4uqQn^xZaoD%Qt}uWlQ=Nagz?>WVjnZi-}2H5Gi3 zW?inR42L`2eH_*i4eAip3Dq`L<@g|gi8+CGBpsw7>mUdgOS_Zvn;tz)zT-==Rb`i< z8@=X2-T%mA9MsB06Bu9ryX%w1n%VA9Dm~o>yT3Y~m%Ti=l6qGIuY4g;_$_&*N2sRpvN>`wicogETy^HHGFFr757C^_H*d{P5C;J9ucEFKVJS@oEr2?xhKnZY) z2_K#1?wKF?u47W}sR@e}4q#Zv3R6OEzOw)>H^;_ub zU(gtPGhV8$cgH^QJqWB0$YyY>-s2Ugbo{aYZl#K7T?+pLx0qWk*Y zrMd?|Xw^Nw9=%NE+d%(Uu!o<{_0fkjdp_71#}EqK;aEapvw8q;yLeAMg>-H^ntu)3 zB+r9iCz6FybL-7$ViDk$mG5y5#m?T}&fiS{*iqe$!jsTIsg_Qnpa*3!q>?BzqlJa` ztY-@)v!c~SnDX7NIvrqGtAQHB1(eDifCE6qmBGV-uov;A$NH+3Pgf}p@Dcf*07ty0 z{>%zB6y;k+EsHn2k6=kRMf-O=K2?)k|IEh zma)DvGDGc9ZpQvNg%(dBay5LE#rhV}qSX{-Z)Lij- z`coWhzl1Hm^8;t7X~c}}w(meIH!ijZ-o5zEGS-owKOiPTp(6(qC8BGuV44p#!@S)?ZTme?LZ;mJ`ir( zj^a5&iiI@$+lH(8*}Oz2eY9}ue&5gq`R`eogk&~yC(#o>Pvj*8B3-ry)a>ZsrpT0Sa1|G|99Ioq?xU>wC0 z{W+ksEzQH?+X?h}P9++);{YmOhp;XtM2*9T2oSIuFZ>s!L z%kbf=!IWFim)lNc3!>!Q#IY0P@W4`@j&W`yh0OlGL-X8f0ygukA(r-3lSmz-OyCOS zr|%mbP+0oZYZmL#1Uz$wLRwR1j_Hl>Z_l@0J2kM5=&wZatgv6@C6A4QL@~g}UOe+% z*S+Rr?Jo>_k48y8=ltRI_*Y?y8Hdxu!TpO2!LMyY!@dCk0bHS{%x1%#n^V#Z&T!r* zjKVGqtv5=29yy-iM&M1bM4l5Qpa3KI3PBVjmiyECb(n%h4Z|h?O0Nng91|DY0X4rg z;QFCshCv34MA)ANDMa;eciZ29#^5$cjYilUoOI$#-9FHiV9zn}((E9UNWEWCmMUpF z+(RGvy8AI5ER&g0B|fiv?KUy4$(9rVWTRDrQS2)MeslIGnyYR#iW9nt=rdJIXI!a68vs2)gNg%Rz~lA^t7uR=y91Zcqt$x7Q0PyD;`C^{tX#QjNaX?$Q6E4sxgO0$0f)eJu2NM*g zP+o3OuqnrVNN$?6K<2E#D7i6^2-hoxIi2Z#RE#nN8MeOl@JW4qf^i1?`lM#uMIjp= z3n~4=;C;kUUgsHah}2K(5e8mH?pt~Lo4b0And~b2-%zaQ4ndGnUy~=Gm^7UVOA6(R zMXuyV^QAeFrZbT>6aRz5>>+Rb((%e`QP#+0+!shF5*~EF;wW$WK$YcLeO6;PTeWQ4 z%taj-*ya_)>KlOEYrUc$%p9@ZW|I;&a`iWa&|#w53E&ZSx-Hls6uK07A;Q&uwp{kb z9if$$2l>3)I}A(G*ZV#2G3d1{w2#mgN|42Ti4ROlJ>zk3cAgad!ZpU3D-zBB))1gC z39IVp+KtR1Qf%o~2M`5cX|#3;$7{y<{-_fQwuU{cs%(*7i>n}fxqqb%p8|9nD^p6l z;7x;i{F(CM5Y`NX-I5R1K|BpvRB5#$;xyZm9pHd!ho8>T8(O_BroeB z6;>3Q5ILo1(ped7Dnd*}`FJ(VP?AJ!lZ}6p#%xA-hxl-%z>~}{4eV~byS*J1pKvlR z-^$aK9lrQPI))I;dE9JvRXWvkjARef*wUA_DD_p z$F5er?P<{%t(;eDPZyOPxNDW@U+-9NKla!Z;{YL&} zZm7Qo;p+!~;m4-Qto8d(q2yqS^ikQMGjy^@8XA=)7fq9OlRhZ89yEzz@;|bu@zFbhJk~ zI|*nlS4B;@bZWxwPw`sZta(woNPDl@TO}^WTmLD=lEReQ%>VAPMFtY|n($&xD#5#7 z{>dMb;<8J#Ht+CN%{<|=Nbo(|dXb6PyvNK*!Sx+AD%n4~xG$zW`$A7)XvP+_xa8um zLACv7bVz<|m(?m{BlOVp`%rH(&|`ijubIQ}Cywx}LeM4UI=0ulT7Aqf^X+dGmG|*q z^gR^=9-iWunEhai`UXu_hAJ^$s)lkze+M!#A?7>WaTp_^U^5DAP)K6yPcayE7?e`( z0?qy{?Qr#8w+my`F~D5vDez*$;mKj|01KUgI!nmbOu>xtS*W_mg<&L%6_wQ=SLJzB zt_Ri65p~uNzmnfdo+W3lICOHxU z6Ij2Z#32iOCxOfo+~>^@qO*haHU%1UpXo*JRX8Q(_;I|f^$!d>K}m6Do`AQ9=VH%F zA$&vHi)tQ(E*qG}YPp4tlQ$z`PWeU0&aeDo;ockLG!O@6d;nFVDQ*Y!8*Qi41R;%` z@u`KVB;Jz-oa~pbtQ|X?ykJw;#*zQz^ebtD)if4J{}C(hlV=nHz6+wt6EvZ*(`|$w zuW`~ZXp^g*K?i`fF>7I;hTc8;i8Ken-{l_`+mWCCF9bb?w!A?I6_rQ1uI7m#$Jy}t z!8S0J*b0l<4Bn{i^9s@)xcMgZe!M))iMa?7dPB0&@6fvxy*WIG{M&5Ttc71Ae_Fas9gx3&As4g3L_GiS=q2y<@WyNcf znvS>Bjxl*^nwF~}+S?#`H8@y^l>5M@_DwcX(I?NjN`Fid2eck|tkNQA+IExCv19z_ zXQ00xI9|(M>2bx&bVgVcyIfL^y8mOUtb-&OrH;JL|9B?w%yIL2%EQPsQi&TMh#o@h z3p{7bxt+ia8JuT{hZy1)`Ws#!2H^#7cpIM9il;C}jj0-Qc>-dZSA~u*pU46yX^4}z zR>Cb%(wIcDnE{sDPhZYY9m@|+X`_%uk@|S7(>D&Xy;$XS^mP*y!1kP`a**jRDuWuJ z7_`zlxX`3=86wJ}2*S7NjbjYPay*oR=+HTUl4~53$-i z!>{`#_edVvYabDc1=4S+vE$Eg;-8gQ?wS-MN256ire^5N0wJvnSE<5-^)ML2^(IPbg zDk8IIGCQ+uv(A{Q9o8|Rvvs%q43LOZACCD$lRUK8w^on)xz~1;Tk2l7^0*pR&3&5C zXXh2yO`15;`~ulOPgp1P}KNc_%JXa`* zH=jrOBt&(br$$H*dftNjoF+;vZ)uq!W>fO0nzX8nL?^@VL{txZiajr1NUiv~h>9no zqS9hg{1D9Aq0Qxan5^cV&sH>x4z=WreDaOs@bSO8?1Ie|$`jQ+2OPD@5f{B`%g~tm zD92hoTx<%Rnze`J^eoj`KVO|Z=+@g@Z$Imfxc<2{@G11De{8;&G0{GE(CL2*PAI|` z)lLN$$_BQEIohTk(S5~`Bcj4yus zuZY+Z5oR&Yqa?rtr7{%cOjWZ_NXTY5Eb4v3ks*!*R9`AYZyA4(QRf?qmA-nJHR!yw z{eGpOsbFEh*j}b4*GWY58;wcg@1l+Y_%A(!yCDBWJX9zUljPiQ+FYRbZ7o&B=lAv$ zt3o{mcQlM+brryLSYHy2C~6Tdn#WY0= zpZG~fg;t7_WRJt{WD;$whuz|9TfPwxErxh*#TOa90~G86x-{BR z2WCmDZpSInmWZuL0VPU+QR|IQ7!)qfB@VQx5x?Sl%SLyGrU*@}3L8a<;nV%B&P@2OHx0nlBfHRWcG?u++m>nJ4XAAg4ddS$tWy;BZ>G-59 z4qFdcNI*)z;rZ~S<_(%S{@;D#Cr8HH0q%Aih8}4^Ah0ehAH;q-1eKIKXc#`=eoxj) zHxN1-q{U1#T%@8;=yB;ysY5r}|Z&rdtR%!+DnZKVi2RjC1 zzw7A}!8JyWkmXE~A}*9)1E5gWc^i@)8qDQ;f&bJN{hfZb;yBL588P92T?W@yKtRbH z#4dSW*zIFgstrZ1zk%dM`8C&fV*l%RM@~LQLkgI1v%p6qRM>UEt;Shu6dvm(dA+j% zBWuuq04p|&mR$@kOEmzOBXF}kWH5|G^FxIIoY{ccTLK02ZeeZ|A|OS{Wj=-j{ zQjb>%bcpaasKo^@|5rJGydi3KI|%pk!Lc5=h%o)*=|cMS-H(f!Rn;L1b?;7N6;Yg+ zE`A4;12m2(Yj21QUrD*_&I9zUP?1SV>9kfOV#&loDe!3pCGvd_{N*&+2U`Zz`m9x6 zT$`e(V6a5}QOoFJV}iM=_j{Xi;~R`n=x_imY(W5*RXqvs7!3Qf^)x<`%Az{r4uDV5 z&;If9e44BGSh&)x2w=JngA_~a0LdD(r(zA6*vbjdchLb!FcJcKB`m~9NU~?{X#l0; zb-Stj>4MIWxf_EY2an{zl<00c4ISRJBoDi(icu%~c0V+16{-15qZ& z4YZI5eE%1kBM~N^+-gTN0&(PlzrrCj0TI7%OtyN$Q2L&&u29W>+vA7FNy|u41HmPs zvfh^?!+#L{eDTJi>A!S+mTSpd54LgD9p? zBCn@2b(gP=;zrWwvx|hryrfWaE;dti!@%3ZwSMUEIzaeJP;*b``SBVligne>VU@9-_oeE23Z=pNqGmImXzG~qhM1O69$ zhBj$GoyG8l#OWl)y3i^Y6-}_jgj7&nw<9@@tis~|esttjIHDETGsViz<55z)q4-lbg8d5r+a)FHf2e=T-M2h=Q8ofoQ5CPtHy{)j_ z@1XcTKo^A`VI>H6U#EL}#eJ!{PHZ*z# zIH{9IYx;pk2p_qp5hAA{#%f*Xl~S9_{Z!&^Fw%#c{ll0?<35q7z4BpkI2&OZSCQw% z9JMF19*7|^b%YyhHFXc?1}sstUm>ytgJrhELvz$}U(hzL`Q2|U>VZL0t&zzEqZQWK zlsHJi6~)S2V{zx~lP5`;{Z}!9NGoAjI*656{Rf1x;as}{;UUB*4CHW&QqbBrcZDE# znGqV-d#VBCQ~(Qk?vEqY>V6AFs_GZu&?(c9J#b=oNRh1X-Pl3)`=ol9-v3p@Z!~dz z6i(F}$@}^LBvy#YB$(}9zKV|7_XqgG<72R8JoEk@Q zi7^^px2`mp!-Yi{#8F?|(t3{LbS!&REY53;V&T{F;`A-xeUWLvczqq?IfqlLpDNSl z=v>PsRx4;b9z3ga3>GMd!_1IWE1g(rbcEK5!^O%#LZX#3RS7L3VbqxyM7Dp1dM28x zG!!;1^1NhZnSrDgh!h&@Oo2TQ`6Z9dM%Z@_aqHYk*(!i1UuhHrm>uEn@SJ1L0FyAY zc{|Qk1P;p%z<4En*wH@-GC#DY4iE8Ov;Hd|=5lpCH_>dxqE}?&AA%>c1TBDox^R9$ z0P-5;3!$|CAg32TVT3-`R^S|FVqgHT0>85v!wXpysWl0M5oO9`C>@E(CwGdt!`sg? zrDINsQ?aux-+&fKO5_7vE#78hZN;Ol@S;3U(Y-C%Rq#dX<=T%>S&Vb`>%F|>bM{Zv zsFrIB<}+=Sj)6BqN5DQ!>(lyLC6t{fQ%zc}(-D^{s8aZe4~IGxeIgzBqtEU!oj;ss3k01hX*=v|h(QJF&=DjZK3nUIst^fQQi-#8NZOpH%ee3dC}j zMwQzg{otsiE$K&MW(a@8I^XPa+8e_;3Q{m4L|aqNneHAjykz%a^gAGuLsqs1n{3*I z(_e_SBy%bT@k#jVXN~5lmx6+b71$|L%cpdB?Jjl@cL9|)Y}8fP@>hv;xcnggBM#Kl z<9-%&0kl7_^rBTs8Ps!i7gnjFI}|mVfsdoZ&WEathD#-I@{>^KZ%zAG5=I0nhy{i@ zEK>D=bWXR|(J=Jq+2fDof&hioiKA3Z1d^Wv391C8COzW|%@;~ih%pWb!tt2{$Jijff%sAenah$saL)Pqi=N*m8^;9^Li@c zf=a}V_+MtmKN2u$px=H6P-kT_2EO#zh ztPN}(fWlz%Q+8(4#%8sMSwj7sR=@hckKAB@_(yffkjb?xhV}3v$OBG$cD5!l0c$^o zne?m5-+-$75!?w60c5n_AwT-kiw7K6o#%^{p{+UqmZi;Kfv?FY_0kORkNg+!$vyxi z;BVYLsfgLl^noWzUu>QBgE}hxIg^gG7_L`cg8mBz1q)Q6GTK{L#f-A(Khd`CXL{@a zijLYRa*lP+8hoFZOEcy;s!W$Z|6LsPq45e$&~~-Xc#1B3#cCw%*liRfzu^4T2DGt>6XL`yRm4 z>!Av07&|cE%&;%pkO5oOdMuVDTwj^C^FLkvfW*Kfj^s#LOz5w6vmYd^RZ$T@6I!qI zpt5y>tUl&Vpy)%W4sH6qnFB+twkuBLMgC*?A68T2GLSxDMKKReGgM{!Pxxm2P{(D} z%gQab`yx#NTRcs$shu`VN*kam22HL+{%`VLggbi5-V8O9(k+;oZ59|Ck3c1XV>5@H z`+*p8jPbG6H^EpRpR6d{p%zDSu9y~)?)`LFZMP}J^>Wd@o1iQgo8ht~`Qa{zsUHFT zH`4--XpEGaZ+sW|Ft^9^$$)u9`oq0ktXvrNQHYNMH%cnnhEm>vCMD$(_x~o-kMkpG zVbm&@?84CgQVmoyvE0a7i%Fq_x_zL5lUmy@cN8!Cu za8CEW?EO-L;moa&#c6L;cc<%qn12NbB7->Q=_Ekd%BXJrH1NOQv={5ZbTyiI*7v*& ziqYf)A`#WVQG_V$P-nBK)cSbRupPCPt}IHFmNM~5fCKv9$N7db4Px^`Bi((3U53-S z9B24XJ^;t3Yk-zlz$_woj`n#G2J#+XKWwRrF^@n(#spCQ+`nnnN+i+irg2(y35CD| zk)Yp%rJr=KE{P${S8>^Giu%p|{Gj}xm}{+OrCL$TfXJ9=afN9b|Nn1ftV9V}ZVnJc z0i4H}2{?D!-`|?KZ|mRerTGQN!13?=SoOVL-eM z7|ZjLk9BEPuuWC(XCbkEZ_4X!MF4G!_&COOdpTCLa~T@xGid*l;pczc!O*NS3Yv=; z9|Mlr^n;&IZ1gvpqcww7ZIMX!G*fsI$}t0|lGdbUkvIFG1Vjnz!S%yWkHT+4q(6dZ zu!@I4B72%r%#@l^wUA14KuqeJ_K&(m6mHBqH40_|7$36;X%xH031CX8f&4(+<#zut zkP)F;_jzwE2Lp0X>Z+(Y3|istfWT>|pbLof<`Mi1lWxu;QoUUt6{-&9O<6M`wkal-x>u>O_hYs*SP#Lzn=AQ$!{Sdea&B|41tMFbSozlO(HdnVGYND z_<%T&WaO?gZXc>OiWILV*)yE!i;< zHNm|%g_beP>n=4wtUdrDX4$SAS@-?zl|a2iEESD7*D_k9p!Ty8%^qg$wVtka^PDYd zoW6<76a%?%%%=n${JUtUjs>6hSAsiR^oY2TDAGC5NZfvdgTM~j4-$2h4;d39tr`V^ zmBixlh(^d>lIdXLZ@@NGwtl-epk$VpTRy&T_iO?Dq$`{CoYRL85Ux@6N#`wmS0UiM z?RgB)?VM>OEr5812Vi_A$O6wjg8Sx#xY{OR;%!X|9SLuyO;mBVs>8wYsaOHn7S#SE z?L@c%C~{CL-=NnkP|(DH=Xy>uAva0a5yW>GAbH|f&sA7}a~|eW;JcX+M$t-&@~{d8 zpn=(bL?cqXi z8@%3rBC=iKKJsfpI%O;c*9bUQ2?~7i5e<#-F6*w%)w#?5o9r$UZY8`f^=36~n zXVD4%|KoS|c%)G`!5-bSg5gs~OjsDEc-AC}IA7J7DN|{Um>M&;Bv6P|E;id#@Zs29 zQKB&MTaX)pR*VBhR<1VoM~I{6EL^1Y@@9czos%V>(C7l^qy&djs&RsPj4BT0vQ+F< zfJ9>q)1b~o_+(vShD#dFe$S7JDBKuc_Zz#5qnw;ZPA4u=kRAQz|5GvjzfiBn7c5FF z-0Rky*7vU%+al+IWXR>#iR?a^Abzo9W`+V03(UIFoJQbrln*gnJ`8on8TA8V$3kbf zbRHfu13Rb;se%*5_MLQfP9-wnSY+0FH%UmrhEI96ZsM9XGISak==MJOCVZaFz{-@M z^E4o1lZi#3{u)E`?z-^4{lxSf-DY%ngcOA~^Il41JL?ZaB68%fTGMowtFN0P0aX@G zQSxcI9pF^q?r5NwS}17i6QC#Ot+dIxarT*+&qQ2Z&PjhnCnQyG=DEmzN6n@q|3M14 zTvmRuathOa4PG&cmz}AR36>UqWVuf}B;Ek96pHEVYxzy3VYkyKKt_GNU)pljbsRl! zKWn$u&f}y$%+umk;~jq;q>J?ykrD?22RuQc^U+RHqcNgRD#(t}zu5Rht#Lx#f$bYx znCULHkx$jDy2&Fez8P@`k@e4CQt<&-ArDvC{R&uTA8|c4DaqLIuWtX;2e2Fv(Fp?a z%EWvprN#uBAirYa#LEQ9jEwPL_FzEhr{g-|@M##&J>85_&?C|IHH2!o<+pQ^w|BuP zbt^C>;Iz;L<<0e0P#Ym0FA%wCE_=!o^|n?T zAk0;jCh+lH0EfV#gxpH)o?n{aL#(J- zXz&Eb^*tb$H;NZwjIJK(^Y)b_CpN4%KR#aw(ymq9B~zFxn^e7_WqU6q_>;})RK9d) zWUrNUx6&qwviSnEd5SQM(?7XovGMzF8N@3N!*pCbF>g~J?XT`UbnirF70+P=&yQT7{~pbUDC!PtwEiqxi&1c&PmF3@%}m@0*dF#e zIvhb$s2n252PHIRJ1?)&EB4$dec4{b`^|_ogDp6_&b?J&{dk;OTfYcGqQekm>q#ld zYT{*rr6R^AYfyyY1#kAGOK>WxXJmjRYnDo+&Qe1auTz$KySG=}t%=u54q$2sr_ zoHt_lJ~^Mhfp6b~hC4|4C-fVyuKfE6=@&mb@c209!F|QGG)}Xvi>cR#pJe#@#r{!+=|!_B;y`Z(LdBwa`hhD7dk#`1%UEm!7X5no;XVYVJHXz;1=xO| zWt1zghAB#F=h4YHz2!Y*xxDk>uuEvbG1RNb?&UtPTb}C2HxYEyL>U+*+}!KPC*`(l z_7k|SDEV5{!unBi&xK9L*SrrirBVClP- zWG^ff_vg|!m3+SFZ`DoEg#HPFYAp@sLq>IjU?Hv=Qzvi9gRYJ?M&ky)IELNn$qK!eZUpiSB7t zZqs-22lMH604hz%=YQ(!43#rmnI?*%+_Imx8^HU!auSHIkgs;rYn>Bc=DY9BIK|Yt z^f%`9cfLGg7t@sK-UfO_e}O=yf?uh4EZ-df$3V%;2RgT-R@h0AnLz)Vb(5Z1V%R6A zz*mMvqu+EOU7=uw#Ek$Ib!h?~m(nNYwe{jh2@G%)B^^_!*cL2k{w$9(F4Y|WP&rgY z75DqIGOZ?W8dfyOyJb!D3<|q_DmzCiAfxd`L`gC7&;(oX+qY24_>;mOE-5IBdTl`W zyMBdZo-9ulSpkkuTO1%Ae8Ky-z!v>XjYA6JJ~#A21gO8PiAYRQxmW3l4!2 z=eF`EDrsBt6ls97P1zAUnwRMp1i!$Q^d7&SY2RJxG^uo<=Ytbi)%9|Hnl%be z-O5G$F(HzKB;4!xA|o1c-fulc(0Bq1WB^C&z0@kkKE4rP=_$XYdA)rW$XQl2bx(Hd6jx z%cp2v!+TsLXetLMUf)}uB{vG%y3Rl-PSbV#_G302(_ks}*1%#1ma;rMFaK@`t=By9 zlGn>$#;_xD!vRkq7AR0xBZ`%`r$)u?-TmA-zhZ_`H|f1cQ9HQ%*xThSH!wwC4i=e8 z+RNat*zJ$fvY#Qo`Ifvs4BkV_SqUD0dlv&}y{Qc9fGqZT#C+JW;gHIE8GKxzWJeRjjWa&@ zsUAoA^X%k4oV23Xnl|ib#zCpl>A`=rtkDhc?bG!^bddeu(&yf{DZHOeSmMF?GukyG zf#cj)pfZZ>%MhVg{1#7@DL9(fP`!lTxYG&Uj#dHC6n6;~c#p1lsWoVBn%i``-Jfa| z%AUz)J0U*yH}gdd;MH5QBbX{`@jyiPY{=})IA3)0U4WZ~CmSWNlC$vTS?IIpcgpo{ zepaz`_EK)KgV%gAPb%oS_{#b?F*9JQrbJed^fCt7UIW_RowDchir(NOn}q%Z$BOQ) zg()WlFF<4y%_v`5WjY6goYK=b^i=S?K4o#tr5@3)a<>Fio_ar(}8jiv)&8)i8Vh zf0fnr%)`d>X9OFt+M7I(ZBTVLR`Dz}pW$wEtAXAc&uFES+SfqUnmzW*HRVbG-lq(s z+@zk9O@4lyJ!_|(eBO{*x>J%n;IWR^*VR7z5<4=yl73q3=`BU##D+=8 z@sT*hhaLZq%M=x@HMOVRN_{iT5SVEHjZ3qV!7X%T4P0$KZ{@ob2#MdVYLZk=?OEGL z*q2K9Xb^ucSf*-)Qk>wNwyVQYj|i`2283l~EPKaG=NB*j$9lzS3{%Y|xDG$TvDB43 zr-MzK-iuJmWwQXKRq29QtXeoKuSdH9ccNcjJu7@CE4(na{%-m*xv?_T=9f{N2;9|5 z`hk#&;e}(R-Zb$!5IUKC^;BB!-mL^ln6Qf3eH|rlUmt;-373i4xsQ9dqlmGJdOAJR z6(F61ut+#B$(=nS-KTC0U245rla_VQ)cvSXuD?;hhU^2X*W#w~Ly9k~blTxiNDc9+ zfF~z@SopIf{NN~@|1%n<`CRaZK03BT-VtpxMo0)h_V&22>!GHiQQL~g`!B3rOX9`` z8f7a6FVsR*zTvqXidnd&|Dw-fHsth~o^HYlMJ0n0DbUzFMMafGX*DEDtk| z3S2Z6XyjwYT}R7j#lvJ{P(Nb~dT*Y|bc$!gyrl%yIjb+}{bb|V*ur>-X_;?Zb2=0C) zeL=iz3wvPqVw@Mj--&%OAZ0YvT{>z<%eq?~kuvzRm;8R_A)No3d-D&3W>A zCd1mxm);(pHBuyFOboe<(6T{XF>KPnu6^qF$&g`>yM`4=c78wySly06H111c?){p94~vv;D8#Ou^K_0(Q? znx=K<_ITRvbNUzIP~DTe* zc7Fl8a&okUIa5@O1{jwq4!1aH;E8}m7d3%brTT!aD@C2tq)#i-~@3l;Ea*`H1pj zwYxa9J(eFHYrOxoD=&RuA(`Ih7|pApYBeOZ>bEm={GU5^w45=16eLpHR1q#$`r*Qz z1A^6z+NE_n$Puf4ia4ed^ADS$(Phb_^-%_#Y?>6aX8c08j@% zZs+FTIP{?1NqG1~ozC5GnMZ&l&~vGdEbrVx?MDX0^~|?hcRpJo{oGuMrds_Zv&97Y{^N4CY+~0PsK$`i=xl0UbX_hO#UJM^?UlS78-F8Z!Ir{Sy zh(VtPcldD5X#!5-%6nv5m;MQ`U zd;hy44RB>MQRc7sX>~}qaH5X*8uof3X6d&m9MfgV{|p+fF}k%n^Gg%R$022Mv|G{k zG%mEEbpv>@XQZ9=M5EdcyIpP@QV!V1vy+O}wH*>h?D@H8*si<9)#xsT$D+1EU5%GV zc7;DwNS9$F9s#~k4aT=v*f?-6>)=DHbHnzKKxL$|!I4*!eI|QA?HK}Y?eEH^$Q<%a zf7x@;4^RIo;v5$}#}~zMY*K(0L7xKQNLNr($J=LJnzrLdt1RNAi`na269`yGx~O@` ztdt;W=z@oFuC&(FDW2rB1Y?}T!d4wJX0i#X>Rdt~-Oj2hZ|__+06>2FGC z=feRYj&k|pL10S23u7%=wO|s zW9Jw|@SGB=W(KJ@UwFH`qum|dH8%yQ(uVwS+U0v-aLW^roPs4FgzDsGf-e~qSNHwp*g`=o z;Rj(MjI?jG`$M1~M}H5%#I>2p*DFUOg<3MZX9K%x;SC`|ftm4hpsjd~pvoCvESgfL zEp~B4QZG9?=c}uw1T3#55v<1C>Cl=4%T$wJShs;QAosewhsd@j&oWTDZ}Fw6)i=iG z9N(JC;Vq=({?#p^c(n)$yOiDk(`{$Z;G9Y7h#)b-bdQW}@J|OW!O37GDXtm*1F?0S zN3eGQ`B7|BXQs7!2|{&7s>GcWC+H18h3Ebcq=zuB#iM<1J%)`DdE)HP*; zXo^>Pib_l)dEwHg#nlqSDX&c~Vpdx`{=qrK)k+z(QC=T%P;AjJ_=NHZ9{l|9**C6O zA(#x$ww@9s*4m>MNbv%d)Vo&CL>5X4ix_+zQ~jeR0>V7YKf@MZq+^=?VRurOxHG+~ zW}TX-@S1WN&zpJB&O}aZfwX-hj-~k>5}RV|Ku8c(|eBZp&tMM literal 0 HcmV?d00001 diff --git a/A-Star/Images/step1.dot b/A-Star/Images/step1.dot new file mode 100644 index 000000000..5785aea4c --- /dev/null +++ b/A-Star/Images/step1.dot @@ -0,0 +1,12 @@ +digraph G { + rankdir=LR; + { A [ label = "g = 0\nh = 3", style = filled, color = deepskyblue1 ] } + { rank = same; B [ label = "g = 1\nh = 2", style = filled, color = lightgrey ]; C [ label = "g = 1\nh = 2", style = filled, color = lightgrey ]; D [ label = "g = 1\nh = 2", style = filled, color = lightgrey ] } + { rank = same; E [ label = "g = \?\nh = 1" ]; F [ label = "g = \?\nh = 1" ]; G [ label = "g = \?\nh = 1" ] } + { H [ label = "g = \?\nh = 0" ] } + A -> { B C D } + B -> E + E -> F + D -> G + G -> H +} diff --git a/A-Star/Images/step1.png b/A-Star/Images/step1.png new file mode 100644 index 0000000000000000000000000000000000000000..a983033a2046b0e1dfc674249f28f08956c3edee GIT binary patch literal 28753 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 LEu|U-i{SqS++pzp literal 0 HcmV?d00001 diff --git a/A-Star/Images/step2.dot b/A-Star/Images/step2.dot new file mode 100644 index 000000000..0c8a9d53d --- /dev/null +++ b/A-Star/Images/step2.dot @@ -0,0 +1,12 @@ +digraph G { + rankdir=LR; + { A [ label = "g = 0\nh = 3", style = filled, color = lightblue ] } + { rank = same; B [ label = "g = 1\nh = 2", style = filled, color = deepskyblue1 ]; C [ label = "g = 1\nh = 2", style = filled, color = lightgrey ]; D [ label = "g = 1\nh = 2", style = filled, color = lightgrey ] } + { rank = same; E [ label = "g = 2\nh = 1", style = filled, color = lightgrey ]; F [ label = "g = \?\nh = 1" ]; G [ label = "g = \?\nh = 1" ] } + { H [ label = "g = \?\nh = 0" ] } + A -> { B C D } + B -> E + E -> F + D -> G + G -> H +} diff --git a/A-Star/Images/step2.png b/A-Star/Images/step2.png new file mode 100644 index 0000000000000000000000000000000000000000..10b4300f406be65ffb0e356666ed5ce965b5ca32 GIT binary patch literal 29088 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 EA5Jd { B C D } + B -> E + E -> F + D -> G + G -> H +} diff --git a/A-Star/Images/step3.png b/A-Star/Images/step3.png new file mode 100644 index 0000000000000000000000000000000000000000..e195e7e8e11651f774405e1ca5be8bff514399dc GIT binary patch literal 30158 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 Of~umXLX{jW`2PX5&nCS9 literal 0 HcmV?d00001 diff --git a/A-Star/Images/step4.dot b/A-Star/Images/step4.dot new file mode 100644 index 000000000..16db76796 --- /dev/null +++ b/A-Star/Images/step4.dot @@ -0,0 +1,12 @@ +digraph G { + rankdir=LR; + { A [ label = "g = 0\nh = 3", style = filled, color = lightblue ] } + { rank = same; B [ label = "g = 1\nh = 2", style = filled, color = lightblue ]; C [ label = "g = 1\nh = 2", style = filled, color = lightblue ]; D [ label = "g = 1\nh = 2", style = filled, color = deepskyblue1 ] } + { rank = same; E [ label = "g = 2\nh = 1", style = filled, color = lightgrey ]; F [ label = "g = \?\nh = 1" ]; G [ label = "g = 2\nh = 1", style = filled, color = lightgrey ] } + { H [ label = "g = \?\nh = 0" ] } + A -> { B C D } + B -> E + E -> F + D -> G + G -> H +} diff --git a/A-Star/Images/step4.png b/A-Star/Images/step4.png new file mode 100644 index 0000000000000000000000000000000000000000..c07f34c80d2d69d1960b66b547c16134541b34ef GIT binary patch literal 30130 zcmZsjb97u`+wQ~0w%w?)ZQFK(iEZ098>_LcHb$eyYSh@)*?qt7JL{Zv&L6Y(TC--) z)-%t2U%%^mCQ4aR3JD$`9t;c&Nk&>+6$}jg40yr7egfVJu^}b_HsCI*QlenB(}YK0 zV8UQB;v(vv;HL)A#v1!LLiMI0&;$e<2Epv)RFQ$fk*42prEvpszZv5kYz>1UK>ifP zq!cejE0OE;G59j@@#J?i-PW`2ei8FBJv-rZF^tpa<1ypWxi0kadP4^X2N4`dN(u`L zY?dgL`nwlqPyo#T8h{K{!^Re?m zh~~*=xcUtNTQFm1vfWHHgtkf)Rbyu+67@+absw7U?yo3yY*Q#1}?t|AfdZAdojVH%G(A*X0O) zKtI;sGxyI#H@+!x(K;_Ab}Wc{umPN?LY&UUVKSr{i}S;!#k5pfNzU%)f-Uyb9{7E8NG!X+djUmoPn6sYh-wsPNTE!AfXHDgpQjnxT9tv9<`N9hP**vX#C6L z?ZE4WGHc33__}TSq5D;*K}o;sJ(+#=G8WM~qVFL=L7=4yl@L);QNmoR2q zl=!)5NT~P{^V$0*5MefSITI634bkM#wKBU;Zd*0B4BB@=96CIRdNi>{MS1yKSq{%J z3pLcdz{5`2G&v-LbtHbi(^-2&OpI6Uqv z^`?Cr;{*}pMSLx)e4e#>nR2TS!ippqBL1A4sAw>4iOpKms{@nm#&ReWcn=zIHC#n= z#AlI8TGJL5DYa)Cx}MoXJZH(evvevkJvXmzLdivhg1(u~&d%~?#7_H$g-;16kq-5%n9ad9M#pzU5T}6#B9xM%WU6N zIfOtBIz(95m(I}b^Y^<09kQ=5z^1|icY-QdPO&utEO%0qM5$!<0t^EnD}eq@!(H zC^*?74K8P9OCO8v846e|K|IKKT{?x15;heJoMkW#OQgearACWLt_0I$`53f}Rv`Jp z-8@wQcO>OZDV;jawczE*JWgIxs6KH|a^E z(!fEGgEF8Pc(lms`B*}nc_b?Fn*UVFM6sWgmLKK!8dz=2g@v!1FrWL$WTg&Ids|R4 z7h+H=W|~?v^*)ks_&sc}dz|Zgznry!9xr!puSQ5t1i3*RoYlc(7A6{+h(pg^`nkK+7uRj`g4C~!acOP*DHg;L%yw*B29O7z_&5>Z$_gcG z)>NmS;}8o_uz7$<-IaV}`Df4$2JLTf{=%7j0X^F~hxbt3*TM*5Rge@JoX62z*z?0h z9pQ=l`FiC`Nq_qeOdz*CnMl6|)Q_?=I#p-l(uP#OY=j_O2_0J;gZFulRL5&5jXJ#o zd?QzuMcd_N_KuvSV^1~9Su$3Q8UQuYi#GGzlaUP!Z1aW7T%Zg&m zl**b71^1Xpo8v>`B4=_6#(iVzdsXEL?RkGbX?8o&#AmaJrSn>;(xC6W=zXb>h{4v} z2p;20(YINs5Lv9!XzJwTy2^nD6c`0pwz%AJr`DhEkb12m`Y*S$L#gA|gZzp&xIdVVI;V71 zVIzhpb9q4?x{wZdGH>>TCJ*gg#DUFz;R=Y_P+?Gyt#WXgoVI2a%N1;{eTH;GE0x0#dj=Z%-D&IxhGSMn7Q2f#SxhOog|=L}5}LNKmEVs^1<^<2-qVR2-I)v>3JkY-8*_v!s! zA!M`r6-2}#lqcDIcuAh)G&hrPMBranRJ>oYpQR_4i~Vao6}ulAV96btVH3)rQh>Xj?q_Bm6XK(WMHJ2?M@MGQm#9LIIo)#g7Qx||OLi|limoYouRs}G&)_3vK} z1Dnh8Emjjrw>)=|S{5tSBJ8`)IDhsJw4b8kBI4#IL5($O*67Mg*sY*+w^J)*i;G1d zx2)GpJXETcqc;|s&?|bZJHbFhLt|~#oH%@y#z2S4B~y<707JTlasS;y_<#lFFF>et z^yzSFv(uZ0%6Z-G=01;xYUj&-eKsrgNv>+Z5@;?qJRa|Y-m!yy`kL^0k&ZDJU!(O5 z`b?FAHy5hw3iw$YjfM_n_9rI&fI@s7CU7VL?jg<*oZ*Jg!#P8v(gn$1$Rja_&ZEz= zGBPTvR_^Yt(ICmurC?|TM9U)YnX$C{dTr;QD${ALdxS3Jq{*#37uB^*<6~T$Q-6Yp z*8ZN+VjP7CaaP2tkA|0_b&qQ?z3RMx@|Er-CpdAJ<^oG)eo3#vjk#R!jnU;%<374A z8I<#Pwz$a7_f{{-XR(H@HiN`CY<{cf?7KN)veBD`!1aH3Y3h!+?z#QfEeN>#yO{S5 zbR;F5u1Jho&ir!Nnl6iBJW_1nu%6Xn+-q=Hv*2w!bin8Rt*^>SO!&j*5HHq7heVkf z6?HDM)~GN4yywC2c&&{IiGWi+%n*+2EX>g5RfYLgcQG}I^Myw6idjfGsQ z7dEw8W16y?RUSqS_G3)9=fx<>VB-N^iQ9#7>r1t=GsfxdMr34U|*AvgL zv^kLY-LF_$4>%q#(C!ER?(y+3cW_v5Zy+}CG$*(_UQ}~y?QwQwrK$TjNVV2KT@e4! zw^%)Q_7xUQ6AmHr?*>0(8%dZOV>qd>FL9cyqQBAa@#Y{KX``3dYw{R6kG`x9f`nO} z+&Po&qvC-vV_Sv$PPxl+t#5@!NR`0S=m1*dLPfo6cUY%Rh;QVV3pw0S7hWU5<+QiB zTXp-J{ClcWK|fULf`LDMp!qCmxMD}g|D>jkP6j6)6oEq0>JfGR@)l+S$=y`-<`zKn z+AdhF7Fkmt>OI6B?wxVbnl=S$rEqpik3!l%u4?~9e1tgoLAKadeQOh` z4niw|WB)~t+?#dJqc%dH1RtAor#KY~xUonyic}bna>Wk~*$|wzS=Y;L5#0t;Xby+X zTwafJTUQUxHK`(OOxhsYegjHHt8>v+j~BGEv#y6}I|>vt0vBv*2$ty9@4Au&-ItVF zv7OtRWqyCQ{k{MEwxMk{rHU5v(x-BJG8yK(eLeLG9|09uhKOZGU{qT@U`#6+V>|MP zSl@>e*ni7$=*{xJJC@j=(957^*1eWULY4lIe!ae(SF#y$U89apCXG7+IzaWwR=%v( z+2u|o@uN{@sP7--NGG!R_Zm>-^iU0})9te!y}rgKGK#z24fc2lVIxA%(VIHm*%n{6 z#Qkas6fNV43RfJsrycAzRB7+)Q-n*6FSOZ0RP_Ds7H@YGgy_nf69k_l8M{tda}WvG zB&@adCc80dmb;;JX6*ak+;c`^H{r_LJ}YD^1F|CSe7wqU9Y!TVZ-AUHnrxfMA>4L?IX3=I<)Qtd-NQ_G%Q@k(W1M6(1d4NGI3i0Z- zU@MVKOdUNf`F9NReq*I%*~X8-ehl>rmXF!w(usjai;_dR1Ex* zKhYa3sG%5Sf&_Fo)-5Nh9v0svrAeGPY*a$hYhvUpo%J;~Jz*tj|>uput*l z*h?FGvGTI5Lc6=aT&_sLh4IZLr&vv|)j21p?YeGkJgnr}p_dB?xV%PAnT7E^nJ;&5 z1SqPnzF&^dt}c-mM3pP4e(bd2tdu{X5Tk2U@2#m~QQkCJ&Kx7fY4}Jt2LB-fDr)J| z&Efp%N>duX5FOq4vHq#>HI}7YCD709q$_jeKsGmF#1tf3^PRF&bt%LLGTWtW8TXWF zHL21N$xeM8ldZ$9SsU9XoY#tPPqAKbs6bZiY!xbuj1Va6@!nCoJ&IA%;riMDqk6-| z7q5HT@Zol76wsJ0m{{9s7yFjt$_;^7{lYyj$;n<(A2+=nc5gYITd6FC)#$W4Jo~#w zuhMcRpY!5}fyc(ax}A{8AQZlUck|SVKnupbtxAFqyx-QbR%WZi22(;@tGhT2kvvOl zxHI$GEqi!e)Njyw>hF)%%=jJwX5Zxor#8W+}b=LcTNo9gAky=UbY07 z7Gq78!rNRd7=zOgG20ju;YizL*&3oT5xZ~wbC?0DbLbIFF_LoJ|(vH+0 z&wUwDQF)hv-RAcfQ5_{IC=Q>sRy(4+KdolkKf)p+UKFx5+rVx9#D{`%9uJNMI4VZl zM#}Nd6AzBtm56!29ozBolFVgMl=Yl18FA;HksNb;)lRZ-uQifm;B#YWtots6Idt&6 z5=6|1uKL?c+mM8S;6y{7KxeYC9lMJ{w2aHaWHqsI_s<_fB&~Qj2nm3Q7(gLE?ZATX zX@OLzaybhW-CT7m<4ema)$Tjw$0w$Cstln)6!U6oG#N(y9XuL8OaG{z`)O5o+TGyu_O#vYX+@6u z#`zSzKee5h?_-0XkJWmNgR*p(a!;ok-abGkRQ0v%?d`nf#Ee&gGeb*wo94Ut1(dDS zV!e=0Nb1=d6MlfwW~a2JCnF2${do6zKJU6%5QU0&m!=FMr}f6jbno%LbM>peBQ9<} z^n;ZKDPD9@8wwQx@Z)(`I(R8zUhk83zR@(+idnbAn>HhcsUol6GkeeuTt__ET+3iL zDL_D=z%y4up@PuKz(8G2u2dGn7Um*U!9z!5$^;%2#OBt`#u-S+$effud1`@vr%=+% z%28UCsy|008HesZ0i)e#$l!8-r8yd@yaGN*_Ut5N$m1k&O+AkCi|eF34QUb93YZ#t zV*=Qvh@bPon4qNd4?#dTotaTc5t0TjIcH?gp28Uz;y)tU-F&DVs);$b1;0hDrvOTu#u1zxgys!JcfT&%L-_hAa%Vkt3A z>;XE%t*hAE-@`uk$3@m0y`(zcD*9#0Lg9W|lsQ_L3^1y$z05JJpQysPYVsERQw1C; zWpPA1>~cB{6AE`JanP8<_>shu^&#@9;-w{AaB0neNDOoOKp;f#G-jdr4``C9Rn>%g zyY;5*c|2>|vYIWDXf_^z07zV_sA>OHo7$S3cPE2T2iE`!0{HP)53_Kh(-B0yF6tKR zMb)dtcVhTYGu~s~Wdc~&I+{?Fie2AfpU3WK<}Lw=GW+LejE2E(906BV7KMV9zkhFX zg>n+;sUTq12rhT!%LjzPC5CM?==b(@X`Z!s(xnYjQm_&w4UgCL*V(+!AJFq)gxB?s zN$`fB`&R7p^O^0qAkXDC3Zcj|*-JpaMa)pg?+5$)Itq}R^*LM)W!Mb5%J)wQ&FA8* zR2Dpp>&A>@-Yh|vjkBh$-GB>hGWJo`KG zc}lxCpo_TO4ndiFe|v$uYV(BSp^JzF^?kg*u)Ciwlf$0MjF%Yb8$<2oo90V&a=pSh z!oktZ6gs3SsF18#^8n&@ed$UG6-7 zDn!yeQhYkcf^~)q$T@ebAr%gO+qW5tA1Ccj1 zdCb{*U}E~Zz0H3q(+!&OIcToLjb|b&Q4ltl&qI;rVscWx;Oiz$4cw9LxXtkmzcl^y zzY`~<=o8olkj6r??&V4(Y_Dcb+K zf9rK~Fbf<6;=jTCys`v*8=ZQSlMI3scKKI=H*1P?Ip+qwrhok*78Vhtdokv&lvnojST-v}|Dr- z-^j$mD`rLh9L<#?*sV6p^sx86obz?wui79HcuAgn@#bYIlxGGFz3`I+{gRK2(mcLp zy+!1lvq6$Wrfg25+kJ!##+^~y_OPb&FqLz`yjvk5sW1+^X#1Gpx`;Bb- zj(zNG9+xsb>h!T>u1v1h*lyqP$*FReZY8sWTEsGlLr4^}PX@F!iGwRI1o>Obp)y^; z`5t+Y2k^s4eB6SCsv~TO39f`LVg0#<=bu8ttN7U2)$JZ@Se&$0lU$&{J^oSsjYuDz zfVDOUt=Pxyfsothle+l|mEzNQR2ePCzE|fv=O&+I0u)l;FBy5O{oPk@`~jjgD8@5iAaM|9kkeU{g3kq17R-66bysg(-Ysw=i-w^)Gg=~)m6EzEa1p{ATC+2mnfZq+?z%S(p zGkF<^%b?jCihQ|&qJ$U(J9t{Ih~i*P~vm<$7^b> z17xjO`>ZfX_~LKRcg1#Vt#Ct(1SQTb|FJuXC4?#M5(XXg4;@*>iZH*Xvhw0ZJ2fSy zL;sgu`UMR*5;_uw@65zRu@s44s`u?*5ru4avL7Y{Sv`|biDQ`mF;*|}{v9q$Z{PP@ zg-u+nIY3BCJvO}}&O1*S4{^ruf&*nxwf~9itw1UwL0@fi0iTBr4+al4z*}0>{967B zIJ01Y4I}87l8b~^NuUBeh*a8f3g4T9sfBhYGs}!ICy{=2*dHS!^8k#hPOc`s$)YNR zMTV6LOXNU8&H|`46FDhJ-tVebC-!N%!ORuF|MSsU^y*Z#05rlLgEe=m^2LIZj|00- zkdl(B4(5vgtXnFJrP0;JZRX(`M~DH{4INZ8q2hp-7CS@*)%*AdLF32n-dM`*VL?Du z5lK2Np@FryB07|OFc^Hmy5kTMCMM=r4@quL(;u*7U{*L}Jlki$Xt=-U`)cMZBO~Mb zcDF=-;aEZ;F*bRBwzkHt<_-t(9@c-kGXyuCc@H~c51=ET2=hMD?K{{=@AVT0m055` z-R4N;4p{U%>H=R;zn6Ok@8DN-s8?L@V_ErrT;ui`d0YbG>#5^yFuyZMJ~FvCv|p<-MP# z_4jVchh({?|2usb}QT0I#~fUYh+Ssgg%m%yaRzu7jm zDqB~4zvp7P;+cZ2{xDkwr{J9`0sjwCW1*IJLlu86Lk^0#5W{*$xq_savC)lFBF>t2bFlQt+bgrQQY@{YWlhHwlxyv`&KwR)x1GtVXqVkZ4wA zR}829dWE%N0k4~^S5)zPi!wNb&J)gGbxF>=gR|2P!d|T(G4xBBE+A%gyO1*%A*@Hd z3d2eWja>%DFXEI}b6{0B9NHztsMCNmCW?UlMOhwSLPWRCz9y3%_X{pV$sQ1T$myY` zq*M-r$Er{*mE}yJNcb2Cfzf#P{{mG{y4>MHJ+MZ2X5_V>WShWWLr$>SaA*5S&}pSH;8wCXF~+v zZq=?V_VvJqeaQu4kjrw_va!F^UJ4m5pMO5n3AOG~6sK8?Lo`E*dy7^%Cobr_g`xHQ z{auHy?Y&Seq5@!0?2g;QEg}%eNJt!*@X{9*ZE-&#I4jmw3W#|=0Pj?@N~Jiw@J((v zIFJHreX#k;R4~~+{{FK$O%5e4#l06oP(a9KV=W1mWE{PgYO>bAX5&Yf! zw)ajL&fngbb9(ia^d7e@TX5AoL4RW8D~NM`Aw+F)uRx_WXeG1l`T(w|+8>Dgm^N@^ zkZ6wp5&T=4VOV4o@Rp{0gRe{D87S6xPgxjEjJ;yy|3p<69QamC!K_ zm}eMB?v5mA(SasnEj9zi?Clw+a<~#UeQy-7(xV0i5(MsX?~dk22*Rn&E-|1G%~nU| z8m&%N*!R!QCUr&$8Z@WnzC3f74sYZd{SKn?RU5MKJIwQ#1N>^(>g)1+?<#3s35VRK zB(rg|^H&d1-ZQ0Xb$4r}O!0AEA?ejfMJqLqWa}_38XFh?fS&X-2S5S2E^27a7AFW+ zC4YN_V4lceDhEoTAqcwuSD;#DAJeGcPH&b;Y^RU$0K#iRG2HD^B_{F+c-K9-fG6B} z=0T-@VAf<&h~*Itlc;_vV6-V#-rk>Y$kA(lR}NU;{LInLiz6`2H@M7TfrwJ?igYaz z9_O?x6Att8oHEvYYDHeEBhJ0uo@fIL=$`6asB9M;!hZkvC(8npHP-CBe5 zG)n{H`K<^N{|a{KOZ5mmM0o??*bv|bly=-$3}#2(Tx+!=7T!G7Pp>CrX`@$za>zgD zvnB~SlqLeU#a(74a4HucUY~A`LQn)RZNmMcS)S8MZGPy`BQgxI4tOYFG{tDVPv{&E zZv`g$K^dcjJB$Q^L#86(Ud>maU7P?Qn{g&8uU>j2_nSaqC!oVfv`ozI(UK^Fg^y5a zno5XfR2Nn;WX20ewHEWKf{@8%l%KfbD#aP9L)8=&krncIHPU7XS--+gWwMBQ^`@67 zH05LUI-4%6EdP?EJSNY>7M2t*1aed2r2+ni99tYPtdQ^^tZ(@#B@0d z|7D=*w#(sk+HIvp?+S6IUREaOX*a=&yB+7)>f%eH+bftt*99Z*v{UXSjf7{k5C;Fi z2XB@rHLHHxM-DU-meF(o9MQ6`s$T8_yu-;qGayo3S~^lTaSmwp2hA+r8_h!(S?8BN zD>ZT7xeN_3k_Po2c!0qI> z%2u!6Q8az6vWyI=(=!EG7ydB<7|NbP#8wOttHFknoor6Bcb>>vXuJh=+7#AC*5DS| zX4mgNV~9}o9($7WtM$pgMoY9*9!DQC`AwaE~tSfpfSqO&uaXkdJk88JKByXdI>r*bxv<@<}rXSK1=g_?KaideTHB(92R zJ?RHp#FxIVcseubC3sOqw;%2Za1f;;{ZwUfgnw)jsA-v;n5oHLU~SFk!L5UH@|0`r z_{uA>oMXY>4Vx3CM=YP;RZ32P-ie-!f|Rg6G@2Zhh^VGM$nIsuvVg%`*&hyqk$gMZ zn~>)RN~5~@CwIStN0rs?YZQ3oO5rn~`@+#oI!4j`RnRZ-Z|y&@?snz%v?1axrRB1R z;3Ot5<+rClj}(+*z&xl`PiM5d7t1+fo3;})s_C9AN22TR>y;O=YW4ZQsdLr?*40Ye zCnMWtYNh;=y58sL>0F*-!Xsr|O44t(VIg0-JTH14tk&C|nynY^n!Rvhid5KM^OGOq6>kTy6ZreJ%>JHM~sJWP~T)q0J7L^5kH^NK^z|@lxu1 z&*0;QO0kNo8k~R8r_j#rf4ym*&;>~uMo)c;J8HvTC}*Cc1{G#r?!jFInL)tQDuU|^ zg_26#Gg773%QX9Ae8cTrJ0I=Ut&G7)Lgq$~%u!jhd6`R6Y|mu#l<7#kkW;KTGM*%W z&N~Gme-eZ=_gu-#UTu^;zKzq@{ffe%Ru3jKDnO<4;ILawtlr^H@VGwD zDB)d%W}v< zy#|5x?^=ww+~;PEHW^FB`K(>&0AWp-7NRc@K(;DoKFdr>12i?>pb7YDv zhin-l-kH!eVxZ44S7l_h9(0@gFTjP4bI~(?L`;3l-Rk|v%5ey86XFqiO9!CxzKKHD9LkrGH7sMpMVz?#VKRi&5 zL58j>H}Tk#I$43M82M)Nw`y&8`G+ru+)zR9W9pRI>U3bg@Uz8;%9-VkrL1W8GqEkj ztQcT?jL%FI-=8KKi+;g)v)`)kQ<23T_r)u*vudb^g@<#r%A<2JlH|I4IxMJ8 z&S7DBW^`|HBH?xn{Ik1@6#_kP3v@oJKS_40yzi}EAFo`O3_Mo&^o!o)G8i?;j3mR& zf#jUrz7FU9|&2Y?Nst=srDN*40OR^NHO z4-FVL7@1>%E4UIsmTZ~!bQ4skBCgKv*8QENdW;B1gWKybSdGDJfmV4Gjr1(*SkFGWU-DbjG9m2=RZ-n z!I;<+@w$>4N3Wj&9E}3%dnPCU@C*Ug{LO_l>T!$vm9O>kHF+s^f{<4*omNz_vSO7( z0;*bEO*8x7`-bK}0Aj^g4zuwC4LOutt=39sm0Cm(b)gQ*5;T5%DRT*{gp|c%W~{l zo8>~i$r8L??$6S633bK*H{gJ|j)%4JC@BqzirvWjh-#ncBL2~3d204w#4$>x3kD8uarXkihohP+wOx&r6uBm!>CbFOEb{7OZ9@v5iT0lQ9nr+Xy zj`PXlK*hi9D*Wmuki0&{2;q8u_Duo}6%#0$*64j?R8%~!-##MI60~%fthG||*Ez03 zKypR@t~08uayH37H(u>`2GmG+Xg+>eQu7HO)OYxBQfv<`(N404_EpTbT0_MsLXVAZ zKWbT-?LiD3o$frf;|tzgF!R5eSF4rbzT_*i+NH4f_$aI;etL0|8n8tZ$H#iPKQx8n z@2MI_dP~ch7D8#twL6^6sr)EXKheMcxjOD6jxTq$V3tfSFMy*sw5UG&pA4K68Jbb? zMwbW1vAM%aqlA|$0f#>(nTWS~#ZFQZq9P~~DdHCC^TQ}b0`6jqHBJCi#pFJ6aOy^} z6bi={J_kIZ<;HB??T!zuw#@3v)3C*5aO%r_YSirj2|=o>R*(Ig=)$&0xA)FWSYO<8 zkq3V({VqGcme#QHD+!u~<8eOSfaL z<$PH*DNmo9mp%Z(9Fm=H_iGx3$W}o>xI&%VS$cEJSM3`S?K-F*$AiTd(O?LD*?J2p zGnpL(0rg$9*Vu+_4(@C;-yqfZ9`Wt|%oZ!hCm(O5k|M(D=Zw%VpeZS|hlI%i(>$Tw zE2QbbQ6r|#1kdAji++FT`v8QSfjEG_3jwe=>(nbGnJgrT@kl?hO9I zY`4aF_l2AQUwuK_creBH{&eN`PYhG`w29o1>dSi+0~5jhC&r(k zubr}T3yFdYdG6*Dy&G?DZ4P}UG1Yj~S?#PO-MFWv0bl%kEH1*Kewp_#y3&?s+POPP z(ffE@os2)P8Rf%0A}z$hmbwd$HUkc=&;E}{31g>^h{nwTy(KY((1l`)vV{fp(hlM8 zt;KsR7Q?~^2lx=0oM&Lz;E9l-IGy1seayCCD<9!{R?23(-3A67I*#9+el(l#{fNPp zz(_2GD`dM|FmR+9xMUW#dwsu_Pc>7}3`{sEUWyK}nk#g_h<#?~8~SA5k6vO@?LR6M z9Eb#5nLBJ>yUId8%^mmum9(=(99uS6`_PxjN&hHI?$Y<(U&K^v>1-f+U-M?p0q;&~ z7H4}Dccqbl>AhaE0jS$O7ySiS9z$e-8uC#3E!f7 zjeD{_ziMv}PMl=3oTf>uMKc}{^Lu}NTBtSP>pX3oi2XYV$^py{wT_X7NRI44D(Ru$ zf8R^|wj}z;(HOo|bQiL8=xH((C*%XE<*AqHvx=#_CuG0d*WJ+0DIvdC;<&R#5px-r z5#d3Ins4q>ZSF6D>PU;92j#a?4vxCry zc)xzfDEVE!Pkjuc5L*G#ZZt7NDjOpG=m7~pB-K^QV=e-P!uY4mUe zf}C?FM%(;Iyt3`o>h17Mz%PTDZuyHZhGK7Y$=%Lkl)_J!Rc4 zNi%rU0`bmYq?}`UUyQt zjQaTPn?#C4-ueM}8Ju4qjrCCkZWGDu_-rtBmbNd$N8vo?{?P_>9F>GF47aV*iQ}3b zVLVDh@9q2q^kvfMSi@-89<*gi(-UY58O<1YSmvJrStr81Yapb9n_ zcjh27h5PI%Ygfvan0|eXY2e_D7wf(Gf$D0K_W3pKumZGp&zR>>N2K)-(WtPD<05Z! zGepi9YIiMZDd}>^hGw|p?maHfxV0Mac(%HL^aNEmyp_qM_D_&^$d|AJwq=cpnutkq zUEjOz-PKPVqhD(deF}UY=U{{hv(XYL=^Afat&{A9+Y7v&U! z80gezD5`t`1q>svksS_m9$2QG?491X;Ne#rP54r=%B=8k2=C*pU*{LoeeYj6{74Pl z)^P1I$O?XSt3NoEAyuMMQK2>2QO-+#X5S-)xjS7^li&O#Kuxl_F z{q#TCLnkei=8h7Wo*qZ4JOTe$Lwv4eP3Px@b1meZaYa7^yCU(!fqa9U6st#G6J!`Q zcvG3U?3nU=xJj6~l_iHBd9}@#R3gkchCgWIhP$(d+q=r?FR(c`fTyCg<^RGU@N(K@ z4jSKSNss*w42)y_NAqP02ByxQ-Q^1fr!CL({${CInwPGr+1&k1FVy-*kd2xRs>ZBx zf=La@8CxI~VTIHgTFKu;_(DZ4pCz0v60K@Z1z)$$)gF(N;Xe^>Pe>6bu&oA~_g6UV z{ecDqo72!Nubut7&1fEi7)^%W;h$Wl?mjWZGH^xJ=ZC+xnSa9PbN_O-(iDNssQ)+p zh*XYbH0hau$}-PRm(L!rIYm*q0TCe%SmegXqlSzC0S&vH+U!(8mVvmQm$}0ULutwN z6<9?Awb)7#40FvYSoVND zcao*edWc~0y9RNr+K`a`doqDIUO{)MXP@M&q)HZjZF{gG(23TKWyC2wPX z%r60&M;-t*3~3=1#XRFIH{`|{AeaUm9z#auDCZrf1Pt3>HaJX<+{hKDvV+ZPDd@B* zXGV6NcdpC!mB@|a8bNGPSp)esQzUfPXIG$bz7o(I&&$GYmiEI56P=|)9obN{Yn#iP zuJuZ#O_HDaTOlqdQ#e|o33fKW7c1ZxNMYRxGq@|wCkVZ3XQD4`YFBC29An87cnx#e zt%{TQUIz6Pj{A%B!-IFp6IgP_*NR7|PG52Pb+~)WvYHo6lyt8X)*fROeM-yE7VXIO zqv4{?2^RZK)b?LXPSQE+UPDwdFe*;4w6M!6U(dQ$*#8ttRZ8}JDz*Fl?sjUo&?wt3 z3v2U1xy1{iIUju3oE0~bZbTStl$-7p;3Clu~b8V=67usTcsoaqG5g- zJ_0P1J8Ddk4j>AaW=7Ol2cX?ra@0%Al%5naJBoC6!HI^>vCX^I`#RlA3Wld=mvQir z1EI(=JHC1-fr9i&+GQBY%|{!Gewi~yK zkkIYXff}IcKRBYp?{~`l<_Au#Um;TpFfW!Ox1>!Ihv}{WT1q!lhvsKxcVCG!Q7K16 z$J(ssch1Jcm+;P=yzR1kzYv%-jP3O7cQTSKdt(|!Js1Bk@zo3<`G3Y8z&s5RgMf9d z=&#_!{*NXt+_di6{_qgUXpZB}PHyOZB^ftzx<*tTLrzbpBGT&c&Jt2!U>wH({tG~1 z`8(KRdltyYm-p-tivM|R?LYz{JHybeI+HxQf74)m+ZvSUZ)Ro&_jKAbCbqVjDbPTo z=lA26DO^>5EAG7D|7w2it2%U|L`T=r~q(H@}b>x|iv+ z6O1Ws0+iDmNCd#qN`*y}gV|b4W{MQ}UPqmCUKa_BF|ko>v(A5lC9)Q;{7Uwk&B^we zDqjyAf4@Sn#tQ2| z)T_ab<|wqR-|uOAcsuRT*Y%4PbIo*m>1-4WnGgtD*h!rvPES>!Mdr zCKX^fYzF>M`&2qthUR{-rGSi>g4$I3d*1NG@)cEL1teEUeS+LsKXP5R<<HRpA?Uz~emsxILQ3D#mBGLj4z@ z@PCme^+iM^0LdotC<3kqJp`4->R;5XUPdzq?Y%`t4M=mM794$)&1RD$a&P-dhTFf7 zU9!j#3}g>?+zUMP~QozEJc&kW&~g4D?@>3 zpM^KjHoUK5B9Y&oJ`sDu6?;thv$GnLoDl5U z;bTV}0RG;AkF9bG=YJJ-)?rm`-`6Jvq`SL2C8fI?L|VGLk?sa5X%LX^kS-A+HSPoO67}*lcQnnYe9SI7S+vIlhjd^tDH^5x8x-@TS_` zHQw+&dX#?k#ovbh>h4T4{>y51JkcT`Qi?YRBANGa$sA9d<;*pSU)kb3qpKt5C|B<( z#l_g+M!q&Ri{FojOFyc}=^A|%$qSUuP8pbBQbSlMGhk4rl*E3N!)JLTCdU=55#HCg zH|oEOffF0Lw9h`-j{O~g7x4e`%<<cZ2#56SUlx~>@k2#x7rTG9 z%XG}em&8|zuCRLhC1J|Ex|j^41_SyK)z@2Q_ zSc^@l@WB6yF$En-Ko+X)ySg8-PwP79PJp&0@NhPO{)7GZ1$TjfHKeIrVLK*V$TbFF zUw*e`7T(=4L2QTTTOVX0Gs>Se5wDcxsJn??z^R(xu-Xn{naN|B2dNKe{{Bv%Pm{_V zR^0(qxIxp4%5{VUa_k|Pk?Y?6GaTH|KFdVrGu_p$x+*Q?{HDK z2u5Sz$@b#vYm+RA$}zO^AlivVB2_M!5r!=ty47!A0iQiy_1k6z)}un52*`bg@t5v4 zd~7(3uZEHz=6eDIW1^ze0{4^Z!cG0owazaphsu&wh^q?iZ2}B5IJHUuJ)RqZLRi!(U#V5DkwT~B<%lL!alHMG`tC#9 z2BIj%Q|f@|8lN)D8rvBZvujZ*9*E6|)lB*OLu26X%$=tQ%p#`UCWJo&;dl)|K|+)r zS(v+gr11l5^#hUUmEnAN>#~Vt+JU2pyCDy6NJ+gIYNmrmmC(QvGlYl2SAF=^iBXN(1eu%vDibxwj_sA?pL z*M3p0eEtss<;fEOnrsFlP@5cA1wkEw2^8hTqM{`7aML8bnQLb?BbTOsW ziZA)ezZN&yP}VmpS|UTi&Yq}KV^ChawjTJDOA&8IPH+f1JEcFr7IYKxoUf`hKch*@ z$Y{KIlL<-sjTra@SZwAM4GoP05MH1#9zOw#fHs-Vsz2Kgb&I zOb=;vP8_q+UP$`0+!hFfAzt^Bt03N9AI=yQtca%;q>Mw6^Gs;bl<(~0+lRN z?As4?%BiHaAQqvU%RMm>djd*{HGKkB6zl%=8Ta|=WzeZJ!|z=B{_VQIM^F^%01_(` zg!=gLV|dD|ewA0>iSv`b4$drFIW?}MuUKWad_2Xmw{mt4jyVa(H!1+-wJM)}?njpo zZU3YxZ8#wkV0}JzqDc4X2CfjD^9n@N?AJaG7n#7h_C_x|?bm;Fuu=qo#o5~mp`oFf z$ho()Rr6lUSL?Ux9J;a-=AlUbo4VAC{7i$w^YytR%FWl=%+RI1fnmD*Rojz?Q42y; z{!3npQeKYD4=z#6z_LBh6Ad)Nr51xofoV5tvX;3SX~$ zdi}1;dzg#ozr$dkVP!GrKlZ*ruy+T1v8KI!)kxWVxhB1Ec1Fwp5}=@-q1g>O(QB_J{?Eaj@ZqYM*@?4QYI(-@ydP7!5PdhIYMrsX4=ytjOJCs};kgAC*Wm^Mb z?p>DSM9*`y)xf8R3alw0n#SbQ_55#L!@#1k=Zb~8!m&(!%d z?fXmv6BlG!EPy$&{Pmh2yLPRSVR!^(ZQC;p{QO;>J{#Rn*MvS(_uTGfYfGeqvAkLa zo8bYVIJAAna*Y`1|NF|lX+h45->$=ymzv!0#a_14bSk4}8CYH>R3=+*Ah!PVk~etZ zsJrNEpW+%!PIS47Z$s{Q-j7Py0zVa(AVgM}rLAMlqE6hX_jbh?*CRT*FR)K&$SABMhCoxMC$Dov6>G;L$n-?@W zs=beoPdIVj9B@mOp{{SvsCWC{_M=8e7P$1|k&qbN*xXx}Abi3c9v&_LG6BNOCD#X$vghBmDqMurB)C$vt2+2ZqF#KJ3R{0Au9=mf#A*juwSs7*)4>(~ZsW*$^t)=bI0$VmeMY z!=J2?DUzbwXem)zjE7{2)X_MhOxkxG%Yp0Tz8)nIq@C;6Mz{O7`TXhMYHK9iwNcd9 zN2sEIy>uref;Cf7Rs9Txf3%diRxK9Rki8OXW3zkjHd!etHE-`P?+$p`lX4xUp;CT7 z7xUm!QztIAM#PdMf!~Wk4FIOUSw`H@L7@|1PG|x)=KgRfJUCE^sK@nynq?&T8q_>g zJ3VJ`NHbS(hem7kWRuU`W7?ztQT>pX!8O2hUt%|I3|>9cJAgoZv-c6CXNlw;gnp2! zeA9q-laVYD00gGSj zSnX4&fRwa!d3a^V(B|nwwLx2o$m5OK->YS(xh>T1MHmkus3GA~?x1Ao5AS#Cc_?jq z4L(&{#icVSurh3e)gYYU3}bbr>p^3$02i3DPnP6#-^S6n7gUKqTw6!i6YI4e zMmUQS1-6bzxE&ezg!{^lQTY+EL=r328K!mwrCK>*(Z5lIqe%W6@D{?eD=*{V6avZo zU$|SBn?>LfX3+61Kzxe!HP z+aVa5)kHlED0HTf7qCa8<6uKRodvZZOZW;Gfc5q&Tj<& zu%G75az14vqq%g7L8Z!in_=z#2S%3f8m)h&D_A~Xz)eP;oyhF>9-*CC7%X;9+8JXp zIgB@1(*4iCr@Q$dF#A#1Q+?m%+;bMnrvoT6XFWI}`C9dkSBoL>8(Wj)DFjXuS-$ zH>+Oj%FoQFD+BZU%9A#%X+E0M3?pB8;hABvXgOkjoi^SdiTf?qZ}V zXnuYDDwS_J53z5CmrY~RPTfHj`l9w7Bd8I-foJP7&+nuV@XQLg7^zjb6ZxnUmjJyE zA`85C38CJutnIeFUVQ_Zdil@!)Qv_so#YJ9bhg!EuRkNh06)8fO2ot9dP6g$z1|cn z*}8~*Pkzwf*QYFT_B!%$^QSMot(%W>ho@QL-!M&dg4Vr~V@TRsAYLZlqvb|hTn`fE zK4Q>!ajNhz2(VT@XN;v?w_Y-L-Jyg{s^ki$iTpjFK3wnV83}|IMHH6HY$0RFszNPe z&S2Fqm0$*TEmZ_`GOcLFGmVD9uZ47xT}VFT=cK=}BOT*SB2ekMjWcRUSB*IAJ$B|ySog6zCkMwVITw%6v^Btg~7`XAi9kvqL>QOHFMSZ_cN;E_h(um7!dfgeLM zV3f6$!9#Q`>WrVA8EJ-%IV8aO0ZhViVU52y7sgCPWUx2LQ}W1Cm%(iYaUO@`TVIG5 z=_XQbN(VFP2@O@{C$&ooC>?#)k?JZM6C9nMK%T~F(Cj<0;{6H1WJ+pDHbkCoRa1w< zutE(au-@ez`La3VDT}RsWi}x8t%1SHcZsv-t>5)0@GbE`Dxh7U*&-2<$;zZe zunV)O-49cPpqKXTR~ z`XXYjz!UMI{)QL?1Of+-=^`GV(T6X6Uy`xr)&YYAB20?8awsc5_F#`tT_4UVYOCCX zI~6jiw_#sNCo}zbfsi0!xQNC`e%A=(ffkvA8eu6>*K_PZs>K@V{+90TNq&m4ajwXo zKYDvBm(L2DB)YKF83ulYp>yJLlg+1M`%Jv#<7yh36i@ld6t`H4Gl)x3B)?5ebboE^ z7|3mSLtSy`>2xeNJE=PM5plbo<)fYs%DAU6jib5Rv(C9xYUw5-$iEGF7~>ZQHCwW?O% zjxTGfyc9`Gk{Mj@7tDcb-3HX5E}s(yte*v1bbGf$u# z+AP?m$B%wHm%{z$RpY7=)&pk4x^{lk6VWvT_=8a%aXAqE;gh z7f_mj%S1aJFFIsnH}>zC493y2oQI8$#5sywigV|M*0D`jopgf#*ALXz6*s zm-C!O4jC9MBX5Ci=rt=j86`s@WCikBjxLF`O zfGO?P>EE=&!V$Ku@CtgA{X|A}d#5GXp31@ODJQiCo^1xl#*&t2!PfDt!_jO9u()00zd=d&5yiPaD{?@U%?R(-~s zT+4_Fgy}2aE7+TKct4;DPlEF1)nIA?UStM04Y^#uw>Whko?BQ`316_w0D7;{PyMbt zH(kFZBCsht`2ucrWv-;~fr9Y|@MgSOM94$NILXa>P72Tf=Yb8dl%i#`mYr;z;RrAw z;!xCu&UM7bjw9=r{)h48r8n;Et*%a*eekq^S+3iJTIlkUL9awl3dKUUAO;9!cxJ? z6}0Z^873ohw(DL)K7iS7$;B7x`HW#`iL&nUi>1%Gx9Qvl?mf^BMkrD8n&o6TEyoD7 zFR(rqgKQ8H+o=%6N?d9VAFC8*`zlZ)Gkel5Rjs4gyhI_^K8m9-LAVUj%e(^aNGVYB zd;&&&Lg29)S;tp23@eto=X)>Lks_Zl6E(B1+{54ZR zgDlJI0^5;Yhx=XUW&|-}xskEo@hgk;`nfvq#AONTD?Li*2;o7y8qUddVK=5Jr^dE# zyPF~1*N#*~qb?fPT#en1MRVS>2~M|*9q5Z9rN^in#rKN2i~5&0-aQyah1gNwdddxL zhUs5_zvCD%GDkt@Fdw@j3J*hE&ch6Irj%<-di^}IY$xDzBmvI)XtfiJLpy!AIoj7t zq|c`8;W>P^;?q&K4kh`71PIG7PL4RxJvH!dpa1gveNc!eYGUuJ30#xf)o;_*fQ9xS z{_HZ!#i-4-WLjs@k1mM0#zU%3llu1vp=t75r;pn%f5b2h^}#sbx|W#$NbGpafp;oN zbG#Kb?39h@KW?dLwo@M1A>tt832p$BcLAlP4OfD$fnu-B8yV zqWy9Y9lrPa(7A7a2GZcWvmzde>4;pC9}bB1Q)OVh)Z~BbDnW@w!%#0>274OUly&;! zN9apD&Tndeh?IM$7e4aF4D?2$hjYYHcrSw_fSL2{A>{0yofJi_W^tAakW+|!tsmer zcy(ku$jZ-5wKK}_Y{~Kob%LMHUIV;Xx~BTN&ni1WbY(Y~1H2@<>iPxdE5tv7pbr}P2Cb3e}E#Wao%pqb50m1uj$+^ByUtDpf zq93Gc*OlG(-K4UgHVDe`qXhr7uFstGMDemU2a?E+AULC3nGfxMxn;oV5N&*#KR9$e zc{6k}Ju~BBKi^MX-j z-g|4jI>crgQ%Jh?uva!>m8Dx!vP8=vj)ohLTm5%({MoH;a}ITm<&UIO^<7e<4z)7K z?2;Wu-eFcDc{({MBSDP5Yx8QUNv^tn^bV+g&@grY2v_>l#%gy+L?%S4_=c%;4hx=)UL!mC$sOAV*D$fRYr{<4P=QGK5Pm8dk(#@Jm8IgY8Ehtc&BtISGC z$0AY=Qh|(JmxJFAPQIflOoVbt z61Bs5v%lX`LsQdc`&;}7bcOThAI2P_pEx}{hR?<#rI1uDX>eS^Tb$Nw@DybrzMI=n zPUm2!$Sg<;5`dnN0_Pd22sW@MI$OL{nFtjQu)TeZgx9w*6|;huDqoi(rR=G z7xD+oyc&?!XOxJsc8Hxi3wb-EFsNU?K>KEq*lW_e5l6$Z_qN%V5x3bw6!bhA73#$w zX0tbhQDm9y2a(XkYXq5bd*aRlOO3xY9;vKNGz zSaC7q-*QGW*lY2yqp0d=tmz9#Iopr+|Ni-KK2nP5C_mI@b{@6mPj$IC6AL@x*ed+uA{!iMh*Nrd9u3djbX=TWH0tx zjMeMfph0-DbJ5qM@x}lk=_Tnthmo8r>3M76{{^? zW6V5Pq%;2pWWG?DaGZI=(sqbr(VEOfcCgaM9V{N)%h0S^X5ZHf@+!%h-WP%Y~fX@CUxFm}K4j(Z#cj zN#;0y7c{JD2RFU+Xv;vlB9rPJW8D`ib$kcX^hQaJIi}V-Aw%_>nkdI>*zp4ps9Jv~ zIuOcvWSi7kcOi=zWjYX1KFQ1vPbkfxjyNYwz;{&XO=(6M9A|ZNJY3^2o4GPo(>P{$ zLJ-;|(o`?L4Q(6+=3mTK9M+N)yMh||%XW=4cjqKjn}`IhrO83H(ETv#lLPh>Qotse zmR`;;Q$)s|5Ov=oQLw^QY54cVgqV@CV<{^?+OyiiCVL^}j~=ba23pZ$D?W|>RI6-a ztB&I?I?m07+{^7K9#yQ@O_U{Hn1r_n5wm%VS-m|}bNJQe2Ye@>l{OkDL^P3Kbe3%f zy@(`PTqfpotn%_Qnj#~qGEu$exfCbyx8Yhf#YCv}vzI9=_c~fEv|oq<;|+2i4n$63 z(SX;K&DBc>&mvs_ymMI7|J^6ySorwsV=QWKk2Y`!%-e=i*GKb3{As+&yZa5LFMkf~V( z^eZB@4m4D2Eoz6YyxTCh#7{doM4uvBkE&bODrgM(OF{n0q66#|LIf%YCjANsnn}|h zbJ&0!AbNZ~#%zKznXhy40`j>q_8E(8CIJuciOC{C_7WlQ9#{u`ItEjSnCvhm3@6JC z(MZ!KWA{(KqTDJXa^dmKH}0a|3EY0Hx#PUQB@Hmc1+4QobC75F^{aUwUGE3=-4gBM zh~(uq?qRcOD;R9xvP=Jo2i<)YyM=OQc?BnK3uor~dFL0JRmHSPv`gO*w8#r*1s1Xa z)Ju3}(MnQ7OO#1|oxSs$2eImOAkN?p_x+oS!G< zz7T#`cvtlE+6{>lZ-4cBQ{o9_)?y_^@aRWsczHuhx2&;NT|%K{$<0~Tw|-skUdv!bl#R+Wg6w0r9cYh);i z?+rKn&Wq_S^33aB1X-OsE9UgasDj7@PMB)u^H`#yLiO1PqM}$|g1Pnw&w4fQaC{VF z=dttFq39P0R1(eg=;Y0T@hY-OBTXOAVY(DQ4UQ7pP$r*XGO6(Q8hqPjc$IB&E&~Gt zb411*;Aj&dX*;99p1$|D!2tF%9}QxCRlY&`m4YklN$BU?Ne-hG;}uwbLdUgEz1?e> zXe~b!;)UJ`=(Wee<68bwglE7fOp5)4j>9fYgvtjwFBa@eS^|-#uhZwg#S!4+#rHPz zgIUi%SM0_+ONb1;lxDbal`pR|!n=XHwJ}<;Csun>Tt%J>!Xnpu`ugpj5e=DmC_4(4 zh}X(x+VNquWejlNjw`Ast(R#DBIyz9>lb5&B09`i29YJdd{Wha{|p{5H64PYrX~AR z*Nq3hv41@z++ay2nLZB*r>t+K>DJUSN>x^ym&GxjYO&GOvF=Fsmttm1M3_HBdLu<{ z-k{O^08ip(0o2BgnZb{LX?2-6%eHO*WZE=7KvI$vnvwQJ&};467Lra`nX$BghxCYW z&=&7 zUOe&W59@Q1cnbzYlk6+~ZRD3;#dH|&|C)=Zq+xo_&LPo9tB|^L(WKkxdo_yCbA9tA zzseDo;n^Wu9&(2e4@B-Ri4kB7NqC%%Jo@(%3 zA|~eYYNOT~H+pKh3O!G?JU6doRXvvEM4zSLo8Cjo=G|&&PHj;Yxh;M>Ed00Z*b8oJ zd~^07s!l9;z|^JR!#mv`S2;M8fPnc#Uml--@UH$3F~7ts$I(&{X@>W%Vd7huk>Wf)%0roByPF(huaMme^llq-{nc!vq#9okvZ7HNj%gQ~al zpjmo0f3~n)FN!QSc1a5xy~TKePF6*7lhlUR_A8#^#$e;oCR|?7{h$Ev?l=P0-(F8Iycp;vXA)G~&u{Sweh#FXhRU}VawWuA`8IVl)tNREjq5{d=_3g17Ej*t2^?+(s(BPySJ+Q!=>~=dDK)kY3*HM+DF&Ol z`x1~r#aV_wG?u7H`qbl?hl`x^5sQTuqv=Zm7we8r$dw_*ma1-N>t$U}`uQU7wW3mz zjh;*jhz4Fz4Trs$i53pgN(eWwk(=>fOewCs~bo zeZe9VJBRz!8Sa28?Is1phr6Pt80kbIWc9^w=4;aQ_+5-rT?b6r|@xe01}gG~q?#<&xnmck5x~te|3O8@RltH3^_0 zG?X7Uk&w?Gfo`&SWw-t`X$y3PsEO~r7T^loAJ?BAWxt@C4JCN!0*6U3-`#Xc!aAl& zXPKpLPH)pDiM3)QEd49}yw$;FhM%XP8DJjo1EQeQwT3CgvoIO<$?4QztZ8_Z|FPF2 zqrGXK)@u-Qo;91iO19S4zFL@6#Cnscgn6lQFIz-emPBY{5^QZ+kn@#@Ntc;X^1Yc))W7v@E<_naDmPX#o2Hu7azX|NIncNIX z#|*l1pgr0Q{VukWI znOL>^%_HIWd-_~Xxyi2&a@iRgKY~4rZ$5Ul!#72g6pn+~;ZRRv8^Uk{XV~O`TL#YQ z030sf9 *H@BM%w0T~mCR9DEtQXz3_SYh_{r!i(r5)`|Ady~|Q#-0C-zS*wg^qDC zOUpviA1ld!i5TJDj@R59ojG`U>^=PC{BX5hVG+3RrjC$3c04JCI1zm0q>#)`~)Sl^f-#y9W>_6VM9 z$RX>GAl|g3+3Ca?a%A8rBmpoqRp`e0`wPM3(_JrD)*UTsYm&7 z^Rs6++dA)vOnOH#)K!KcEk|(Z(@H~jY=e<44 z3|6RQO(Pyha&G7l09@l(W6k^lb+lnPf0I4C8Y`N4Uo1W}#l=zh!RK0O^3mT1BESFKm$it*3zXi-kFpv&kq-HTk;!=7jYw_1g^r^ zSBXEYp%IV3bR=G=hff~yUH4j}RU&f~EM?});VRHG~8cWi0h__u!v&dkd zdtD&}dKojSp(dq$9wi9fdk}2N1xS|+5t-c{3ged6lH``iu=nY4z3a1c2DN&+t*<;| zYqY^}H<^(7?wYiTx1*XQ6{mez7qPwdu3n-F!{st$FG#=2U5q6kFY57gwJxMd)E z-EQyruQOh8G*zz=HR4M|M<{PBslP9jm!Plhuh-rZg4WTx;d=5kZlbK=xvRg+JC^P7 zP8M?AiQ;}x$>wF9R|-u`&=6ja!ZB`lFCPdaIn#)3BCye&XjVCr>nXKSaw}{&D zTfw;ER*kwhsw@oP8qmf#D3&g+#`JnzPY+@195dHO)GFp8^qF^`ZFk*Opev*>bXe>3 znT9}^fJFHFm`w+Tfcp3y;?jj0qQ6;~T!(GC)bNpGFwJC}V_j~cu!WzjG z9U=kOVlf>(e8kb(F0*-O%7q7j2GsB{G&c(g3Ua~s0gB5UJVl~rpP!vWS@|tJRS1EN zEYvvfxol8BCA~4uZIf-L&A9B9sGA2mgXx4;fM6+YwLsv9*DyEEQ|*m(dEvqM89Zr> zqz4{50Td}YQ8tM7r)yoXs}|b!fq+K%$YB~Hw(@)P>eo8yl~i2Q0F}kBaEXmuB4yYa zDk^pxU5+T0<9-3xtZX-`o&Xi|s0Z0U9XmIzZf!Z0I=jhwJ!u*|p>D-o_-QNCldjw+ zijuVTEiJqY_3#AZDig)P=^76JESg*IN6{FE)2NF7p zEt{rj{FsS4S>84sJXzQR8(i8EbOuK|2rYPandcCjfN=8$kcRl?-D@RwhE1x)icQRo zZ+{=TsRFg!Zt-8G2r9pA-ETB5Hk=S7j;|Y7!%ZR};@fkLkt>$}b=CB%yuQXY+P-95E{NR}7$yMuD zAyd+EO>KN?!?Poeyx*6*p*mw8|ij-6CBz< z6a-|ck2NM6JP^X5-hT<4rM1*quNm%5XVx{}zEpSl z-dUCOAcD~_0e(u)h$K;)4Q~uT7KQ*n6M+a2m~1xwq;=Z;aN=2VLqm zVI{2ZHUY%XHGI^cDn}DJ7Z(^!WP4uNKJa=aUMbnpG5Xy*T zY!?CFZ;1ZPf3;_=rb<_v%fB%YEVkoBi}_^G?XUMOk^Iz%4!G0^6xYu-7wpNIcKc32t|N{&wpP=6hX*F}4o&CSgC7eqSegMxH7-;Vr= zSI%3udGf#dGlG{l=i9Eo57fOxQyQdG??5J;LC=}Owso#m|n_ zY@Yf%2@QM!yF(uB2+`<4!_n^|i%*5UuNG`(K72p)E#i2&`$p6vTs_7pzwZrnJ|7KQ zFn02dN!;pK0N$%F0nv7ohcO z7#p8b-TW;5Ce;E{k6@r!`phJewtV>G=}!N<1PyKE5V| z(6G(AQZVyfv2f%A>Z;jeLfYm<{3F*`KdESH}+rd6ir>grR&dVA8EI_B5| zbVW}q_Tpp`RCE6BzeZn+2**+QE7% z{Ov1tzs|BkkA>OUFREjQ{;Q1)AES1L41eQG%JoHv$DnpZw`RyJ~}nutLd8t4P&In1uX4voE8G literal 0 HcmV?d00001 diff --git a/A-Star/Images/step5.dot b/A-Star/Images/step5.dot new file mode 100644 index 000000000..2986b6a90 --- /dev/null +++ b/A-Star/Images/step5.dot @@ -0,0 +1,12 @@ +digraph G { + rankdir=LR; + { A [ label = "g = 0\nh = 3", style = filled, color = lightblue ] } + { rank = same; B [ label = "g = 1\nh = 2", style = filled, color = lightblue ]; C [ label = "g = 1\nh = 2", style = filled, color = lightblue ]; D [ label = "g = 1\nh = 2", style = filled, color = lightblue ] } + { rank = same; E [ label = "g = 2\nh = 1", style = filled, color = deepskyblue1 ]; F [ label = "g = 3\nh = 1", style = filled, color = lightgrey ]; G [ label = "g = 2\nh = 1", style = filled, color = lightgrey ] } + { H [ label = "g = \?\nh = 0" ] } + A -> { B C D } + B -> E + E -> F + D -> G + G -> H +} diff --git a/A-Star/Images/step5.png b/A-Star/Images/step5.png new file mode 100644 index 0000000000000000000000000000000000000000..40a7008da206816baa056fa95d9f69c5b6db89ad GIT binary patch literal 29802 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 Y>gT576&OA6;h``x5{lwgqQ=4h3tFTHY5)KL literal 0 HcmV?d00001 diff --git a/A-Star/Images/step6.dot b/A-Star/Images/step6.dot new file mode 100644 index 000000000..b5e3179b6 --- /dev/null +++ b/A-Star/Images/step6.dot @@ -0,0 +1,12 @@ +digraph G { + rankdir=LR; + { A [ label = "g = 0\nh = 3", style = filled, color = lightblue ] } + { rank = same; B [ label = "g = 1\nh = 2", style = filled, color = lightblue ]; C [ label = "g = 1\nh = 2", style = filled, color = lightblue ]; D [ label = "g = 1\nh = 2", style = filled, color = lightblue ] } + { rank = same; E [ label = "g = 2\nh = 1", style = filled, color = lightblue ]; F [ label = "g = 3\nh = 1", style = filled, color = lightgrey ]; G [ label = "g = 2\nh = 1", style = filled, color = deepskyblue1 ] } + { H [ label = "g = 3\nh = 0", style = filled, color = lightgrey ] } + A -> { B C D } + B -> E + E -> F + D -> G + G -> H +} diff --git a/A-Star/Images/step6.png b/A-Star/Images/step6.png new file mode 100644 index 0000000000000000000000000000000000000000..9e7baef2622aaea8538f6f4fcfce9fc732f5403d GIT binary patch literal 29596 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 z

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 literal 0 HcmV?d00001 diff --git a/A-Star/Images/step7.dot b/A-Star/Images/step7.dot new file mode 100644 index 000000000..c5b26b6b3 --- /dev/null +++ b/A-Star/Images/step7.dot @@ -0,0 +1,12 @@ +digraph G { + rankdir=LR; + { A [ label = "g = 0\nh = 3", style = filled, color = lightblue ] } + { rank = same; B [ label = "g = 1\nh = 2", style = filled, color = lightblue ]; C [ label = "g = 1\nh = 2", style = filled, color = lightblue ]; D [ label = "g = 1\nh = 2", style = filled, color = lightblue ] } + { rank = same; E [ label = "g = 2\nh = 1", style = filled, color = lightblue ]; F [ label = "g = 3\nh = 1", style = filled, color = lightgrey ]; G [ label = "g = 2\nh = 1", style = filled, color = lightblue ] } + { H [ label = "g = 3\nh = 0", style = filled, color = deepskyblue1 ] } + A -> { B C D } + B -> E + E -> F + D -> G + G -> H +} diff --git a/A-Star/Images/step7.png b/A-Star/Images/step7.png new file mode 100644 index 0000000000000000000000000000000000000000..0eedd638f24c57f671dc6905bc7910369436fbe5 GIT binary patch literal 30012 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 Date: Wed, 10 Jan 2018 22:18:14 -0800 Subject: [PATCH 008/271] add update to readme --- Red-Black Tree/README.markdown | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Red-Black Tree/README.markdown b/Red-Black Tree/README.markdown index 74fffa415..6db827ea6 100644 --- a/Red-Black Tree/README.markdown +++ b/Red-Black Tree/README.markdown @@ -39,6 +39,9 @@ Tree: * `insert(key:)` Inserts the key value into the tree * `delete(key:)` Delete the node with the respective key value from the tree * `verify()` Verifies that the given tree fulfills the red-black tree properties +* `count()` Returns how many nodes in the tree +* `isEmpty()` Returns if the tree has no nodes +* `allElements()` Returns an array containing all nodes (in-order traversal) in the tree. The rotation, insertion and deletion algorithms are implemented based on the pseudo-code provided in [CLRS] From b59cd5f6b28130146cd03384e926ac5c4ff2622d Mon Sep 17 00:00:00 2001 From: Blaine Rothrock Date: Fri, 23 Feb 2018 15:30:42 -0600 Subject: [PATCH 009/271] working on readme.. finally finishing this PR --- Genetic/README.markdown | 169 ++++++++++++++++++- Genetic/gen.playground/Contents.swift | 91 ++++++++++ Genetic/gen.playground/contents.xcplayground | 4 + Genetic/gen.swift | 38 +++-- 4 files changed, 282 insertions(+), 20 deletions(-) create mode 100644 Genetic/gen.playground/Contents.swift create mode 100644 Genetic/gen.playground/contents.xcplayground diff --git a/Genetic/README.markdown b/Genetic/README.markdown index 7cad649cb..fd208a19d 100644 --- a/Genetic/README.markdown +++ b/Genetic/README.markdown @@ -1,2 +1,167 @@ -# todo -refactoring https://gist.github.com/blainerothrock/efda6e12fe10792c99c990f8ff3daeba for swift 4. Creating a tutorial and writing in more playground friendly format +# Genetic Algorthim + +## What is it? + +A genetic algorithm (GA) is process inspired by natural selection to find high quality solutions. Most commonly used for optimization. GAs rely on the bio-inspired processes of natural selection, more specifically the process of selection (fitness), mutation and crossover. To understand more, let's walk through these process in terms of biology: + +### Selection +>**Selection**, in biology, the preferential survival and reproduction or preferential elimination of individuals with certain genotypes (genetic compositions), by means of natural or artificial controlling factors. [Britannica](britannica) + +In other words, survival of the fittest. Organism that survive in their environment tend to reproduce more. With GAs we generate a fitness model that will rank offspring and give them a better chance for reproduction. + +### Mutation +>**Mutation**, an alteration in the genetic material (the genome) of a cell of a living organism or of a virus that is more or less permanent and that can be transmitted to the cell’s or the virus’s descendants. [Britannica](https://www.britannica.com/science/mutation-genetics) + +The randomization that allows for organisms to change over time. In GAs we build a randomization process that will mutate offspring in a populate in order to randomly introduce fitness variance. + +### Crossover +>**Chromosomal crossover** (or crossing over) is the exchange of genetic material between homologous chromosomes that results in recombinant chromosomes during sexual reproduction [Wikipedia](https://en.wikipedia.org/wiki/Chromosomal_crossover) + +Simply reproduction. A generation will a mixed representation of the previous generation, with offspring taking data (DNA) from both parents. GAs do this by randomly, but weightily, mating offspring to create new generations. + +### Resources: +* [Wikipedia]() + + +## The Code + +### Problem +For this quick and dirty example, we are going to obtain a optimize string using a simple genetic algorithm. More specifically we are trying to take a randomly generated origin string of a fixed length and evolve it into the most optimized string of our choosing. + +We will be creating a bio-inspired world where the absolute existence is string `Hello, World!`. Nothing in this universe is better and it's our goal to get as close to it as possible. + +### Define the Universe + +Before we dive into the core processes we need to set up our "universe". First let's define a lexicon, a set of everything that exists in our universe. + +```swift +let lex: [UInt8] = " !\"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~".asciiArray +``` + +To make things easier, we are actually going to work in ASCII values, so let's define a String extension to help with that. + +```swift +extension String { + var asciiArray: [UInt8] { + return [UInt8](self.utf8) + } +} +``` + + Now, let's define a few global variables for the universe: + + ```swift +// This is the end goal and what we will be using to rate fitness. In the real world this will not exist +let OPTIMAL:[UInt8] = "Hello, World".asciiArray + +// The length of the string in our population. Organisms need to be similar +let DNA_SIZE = OPTIMAL.count + +// size of each generation +let POP_SIZE = 50 + +// max number of generations, script will stop when it reach 5000 if the optimal value is not found +let GENERATIONS = 5000 + +// The chance in which a random nucleotide can mutate (1/n) +let MUTATION_CHANCE = 100 + ``` + + The last piece we need for set up is a function to give us a random ASCII value from our lexicon: + + ```swift + func randomChar(from lexicon: [UInt8]) -> UInt8 { + let len = UInt32(lexicon.count-1) + let rand = Int(arc4random_uniform(len)) + return lexicon[rand] + } + ``` + + ### Population Zero + + Before selecting, mutating and reproduction, we need population to start with. Now that we have the universe defined we can write that function: + + ```swift + func randomPopulation(from lexicon: [UInt8], populationSize: Int, dnaSize: Int) -> [[UInt8]] { + + let len = UInt32(lexicon.count) + + var pop = [[UInt8]]() + + for _ in 0.. Int { + var fitness = 0 + for c in 0...dna.count-1 { + fitness += abs(Int(dna[c]) - Int(optimal[c])) + } + return fitness +} +``` + +The above is a very simple fitness calculation, but it'll work for our example. In a real world problem, the optimal solution is unknown or impossible. [Here](https://iccl.inf.tu-dresden.de/w/images/b/b7/GA_for_TSP.pdf) is a paper about optimizing a solution for the famous [traveling salesman problem](https://en.wikipedia.org/wiki/Travelling_salesman_problem) using GA. In this example the problem is unsolvable by modern computers, but you can rate a individual solution by distance traveled. The optimal fitness here is an impossible 0. The closer the solution is to 0, the better chance for survival. + +The second part to selection is weighted choice, also called roulette wheel selection. This defines how individuals are selected for the reproduction process out of the current population. Just because you are the best choice for natural selection doesn't mean the environment will select you. The individual could fall off a cliff, get dysentery or not be able to reproduce. + +Let's take a second and ask why on this one. Why would you not always want to select the most fit from a population? It's hard to see from this simple example, but let's think about dog breeding, because breeders remove this process and hand select dogs for the next generation. As a result you get improved desired characteristics, but the individuals will also continue to carry genetic disorders that come along with those traits. This is essentially leading the evolution down a linear path. A certain "branch" of evolution may beat out the current fittest solution at a later time. + +ok, back to code. Here is our weighted choice function: + +```swift +func weightedChoice(items:[(item:[UInt8], weight:Double)]) -> (item:[UInt8], weight:Double) { + + let total = items.reduce(0.0) { return $0 + $1.weight} + + var n = Double(arc4random_uniform(UInt32(total * 1000000.0))) / 1000000.0 + + for itemTuple in items { + if n < itemTuple.weight { + return itemTuple + } + n = n - itemTuple.weight + } + return items[1] +} +``` + +The above function takes a list of individuals with their calculated fitness. Then selects one at random offset by their fitness value. + +## Mutation + +The all powerful mutation. The great randomization that turns bacteria into humans, just add time. So powerful yet so simple: + +```swift +func mutate(dna:[UInt8], mutationChance:Int) -> [UInt8] { + var outputDna = dna + + for i in 0..?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~".asciiArray + +// This is the end goal and what we will be using to rate fitness. In the real world this will not exist +let OPTIMAL:[UInt8] = "Hello, World".asciiArray + +// The length of the string in our population. Organisms need to be similar +let DNA_SIZE = OPTIMAL.count + +// size of each generation +let POP_SIZE = 50 + +// max number of generations, script will stop when it reach 5000 if the optimal value is not found +let GENERATIONS = 5000 + +// The chance in which a random nucleotide can mutate (1/n) +let MUTATION_CHANCE = 100 + +func randomChar(from lexicon: [UInt8]) -> UInt8 { + let len = UInt32(lexicon.count-1) + let rand = Int(arc4random_uniform(len)) + return lexicon[rand] +} + +func randomPopulation(from lexicon: [UInt8], populationSize: Int, dnaSize: Int) -> [[UInt8]] { + + let len = UInt32(lexicon.count) + + var pop = [[UInt8]]() + + for _ in 0.. Int { + + var fitness = 0 + for c in 0...dna.count-1 { + fitness += abs(Int(dna[c]) - Int(optimal[c])) + } + return fitness +} + +calculateFitness(dna: "Hillo, World".asciiArray, optimal: "Hello, World".asciiArray) + +func weightedChoice(items:[(item:[UInt8], weight:Double)]) -> (item:[UInt8], weight:Double) { + + let total = items.reduce(0.0) { return $0 + $1.weight} + + var n = Double(arc4random_uniform(UInt32(total * 1000000.0))) / 1000000.0 + + for itemTuple in items { + if n < itemTuple.weight { + return itemTuple + } + n = n - itemTuple.weight + } + return items[1] +} + +func mutate(dna:[UInt8], mutationChance:Int) -> [UInt8] { + var outputDna = dna + + for i in 0.. + + + \ No newline at end of file diff --git a/Genetic/gen.swift b/Genetic/gen.swift index 72830b8a7..17df6d002 100644 --- a/Genetic/gen.swift +++ b/Genetic/gen.swift @@ -14,14 +14,16 @@ extension String { } } +let lex = " !\"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~".map { } + /* helper function to return a random character string */ func randomChar() -> UInt8 { - + let letters : [UInt8] = " !\"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~".asciiArray let len = UInt32(letters.count-1) - + let rand = Int(arc4random_uniform(len)) return letters[rand] } @@ -40,7 +42,7 @@ let MUTATION_CHANCE = 100 optimal string comparsion = 0 */ func calculateFitness(dna:[UInt8], optimal:[UInt8]) -> Int { - + var fitness = 0 for c in 0...dna.count-1 { fitness += abs(Int(dna[c]) - Int(optimal[c])) @@ -53,7 +55,7 @@ func calculateFitness(dna:[UInt8], optimal:[UInt8]) -> Int { */ func mutate(dna:[UInt8], mutationChance:Int, dnaSize:Int) -> [UInt8] { var outputDna = dna - + for i in 0.. [UInt8] { */ func crossover(dna1:[UInt8], dna2:[UInt8], dnaSize:Int) -> (dna1:[UInt8], dna2:[UInt8]) { let pos = Int(arc4random_uniform(UInt32(dnaSize-1))) - + let dna1Index1 = dna1.index(dna1.startIndex, offsetBy: pos) let dna2Index1 = dna2.index(dna2.startIndex, offsetBy: pos) - + return ( [UInt8](dna1.prefix(upTo: dna1Index1) + dna2.suffix(from: dna2Index1)), [UInt8](dna2.prefix(upTo: dna2Index1) + dna1.suffix(from: dna1Index1)) @@ -85,12 +87,12 @@ func crossover(dna1:[UInt8], dna2:[UInt8], dnaSize:Int) -> (dna1:[UInt8], dna2:[ returns a random population, used to start the evolution */ func randomPopulation(populationSize: Int, dnaSize: Int) -> [[UInt8]] { - + let letters : [UInt8] = " !\"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~".asciiArray let len = UInt32(letters.count) var pop = [[UInt8]]() - + for _ in 0.. (item:[UInt8], wei for itemTuple in items { weightTotal += itemTuple.weight; } - + var n = Double(arc4random_uniform(UInt32(weightTotal * 1000000.0))) / 1000000.0 for itemTuple in items { @@ -133,36 +135,36 @@ func main() { for generation in 0...GENERATIONS { print("Generation \(generation) with random sample: \(String(bytes: population[0], encoding:.ascii)!)") - + var weightedPopulation = [(item:[UInt8], weight:Double)]() - + // calulcated the fitness of each individual in the population // and add it to the weight population (weighted = 1.0/fitness) for individual in population { let fitnessValue = calculateFitness(dna: individual, optimal: OPTIMAL) - + let pair = ( individual, fitnessValue == 0 ? 1.0 : 1.0/Double( fitnessValue ) ) - + weightedPopulation.append(pair) } - + population = [] - + // create a new generation using the individuals in the origional population for _ in 0...POP_SIZE/2 { let ind1 = weightedChoice(items: weightedPopulation) let ind2 = weightedChoice(items: weightedPopulation) - + let offspring = crossover(dna1: ind1.item, dna2: ind2.item, dnaSize: DNA_SIZE) // append to the population and mutate population.append(mutate(dna: offspring.dna1, mutationChance: MUTATION_CHANCE, dnaSize: DNA_SIZE)) population.append(mutate(dna: offspring.dna2, mutationChance: MUTATION_CHANCE, dnaSize: DNA_SIZE)) } - + fittest = population[0] var minFitness = calculateFitness(dna: fittest, optimal: OPTIMAL) - + // parse the population for the fittest string for indv in population { let indvFitness = calculateFitness(dna: indv, optimal: OPTIMAL) From c6381646601bb162f650106c2e8ddcd4c9cb86f6 Mon Sep 17 00:00:00 2001 From: Blaine Rothrock Date: Fri, 23 Feb 2018 16:05:01 -0600 Subject: [PATCH 010/271] readme updates --- Genetic/README.markdown | 30 +++++++++++++++++-- Genetic/gen.playground/Contents.swift | 19 ++++++++++-- .../contents.xcworkspacedata | 7 +++++ 3 files changed, 50 insertions(+), 6 deletions(-) create mode 100644 Genetic/gen.playground/playground.xcworkspace/contents.xcworkspacedata diff --git a/Genetic/README.markdown b/Genetic/README.markdown index fd208a19d..6ebbf2cf7 100644 --- a/Genetic/README.markdown +++ b/Genetic/README.markdown @@ -114,7 +114,9 @@ func calculateFitness(dna:[UInt8], optimal:[UInt8]) -> Int { } ``` -The above is a very simple fitness calculation, but it'll work for our example. In a real world problem, the optimal solution is unknown or impossible. [Here](https://iccl.inf.tu-dresden.de/w/images/b/b7/GA_for_TSP.pdf) is a paper about optimizing a solution for the famous [traveling salesman problem](https://en.wikipedia.org/wiki/Travelling_salesman_problem) using GA. In this example the problem is unsolvable by modern computers, but you can rate a individual solution by distance traveled. The optimal fitness here is an impossible 0. The closer the solution is to 0, the better chance for survival. +The above will produce a fitness value to an individual. The perfect solution, "Hello, World" will have a fitness of 0. "Gello, World" will have a fitness of 1 since it is one ASCII value off from the optimal. + +This example is very, but it'll work for our example. In a real world problem, the optimal solution is unknown or impossible. [Here](https://iccl.inf.tu-dresden.de/w/images/b/b7/GA_for_TSP.pdf) is a paper about optimizing a solution for the famous [traveling salesman problem](https://en.wikipedia.org/wiki/Travelling_salesman_problem) using GA. In this example the problem is unsolvable by modern computers, but you can rate a individual solution by distance traveled. The optimal fitness here is an impossible 0. The closer the solution is to 0, the better chance for survival. The second part to selection is weighted choice, also called roulette wheel selection. This defines how individuals are selected for the reproduction process out of the current population. Just because you are the best choice for natural selection doesn't mean the environment will select you. The individual could fall off a cliff, get dysentery or not be able to reproduce. @@ -146,13 +148,13 @@ The above function takes a list of individuals with their calculated fitness. Th The all powerful mutation. The great randomization that turns bacteria into humans, just add time. So powerful yet so simple: ```swift -func mutate(dna:[UInt8], mutationChance:Int) -> [UInt8] { +func mutate(lexicon: [UInt8], dna:[UInt8], mutationChance:Int) -> [UInt8] { var outputDna = dna for i in 0.. (dna1:[UInt8], dna2:[UInt8]) { + let pos = Int(arc4random_uniform(UInt32(dnaSize-1))) + + let dna1Index1 = dna1.index(dna1.startIndex, offsetBy: pos) + let dna2Index1 = dna2.index(dna2.startIndex, offsetBy: pos) + + return ( + [UInt8](dna1.prefix(upTo: dna1Index1) + dna2.suffix(from: dna2Index1)), + [UInt8](dna2.prefix(upTo: dna2Index1) + dna1.suffix(from: dna1Index1)) + ) +} +``` + +The above is used to generate a completely new generation based on the current generation. + +## Putting it all together -- Running the Genetic Algorithm + +We now have all the methods we need to kick off the process. What is missing a `main()` function that loops though each generation of the GA. diff --git a/Genetic/gen.playground/Contents.swift b/Genetic/gen.playground/Contents.swift index b84fd13e3..50d4c4fc8 100644 --- a/Genetic/gen.playground/Contents.swift +++ b/Genetic/gen.playground/Contents.swift @@ -60,7 +60,7 @@ func calculateFitness(dna:[UInt8], optimal:[UInt8]) -> Int { return fitness } -calculateFitness(dna: "Hillo, World".asciiArray, optimal: "Hello, World".asciiArray) +calculateFitness(dna: "Gello, World".asciiArray, optimal: "Hello, World".asciiArray) func weightedChoice(items:[(item:[UInt8], weight:Double)]) -> (item:[UInt8], weight:Double) { @@ -77,15 +77,28 @@ func weightedChoice(items:[(item:[UInt8], weight:Double)]) -> (item:[UInt8], wei return items[1] } -func mutate(dna:[UInt8], mutationChance:Int) -> [UInt8] { +func mutate(lexicon: [UInt8], dna:[UInt8], mutationChance:Int) -> [UInt8] { var outputDna = dna for i in 0.. (dna1:[UInt8], dna2:[UInt8]) { + let pos = Int(arc4random_uniform(UInt32(dnaSize-1))) + + let dna1Index1 = dna1.index(dna1.startIndex, offsetBy: pos) + let dna2Index1 = dna2.index(dna2.startIndex, offsetBy: pos) + + return ( + [UInt8](dna1.prefix(upTo: dna1Index1) + dna2.suffix(from: dna2Index1)), + [UInt8](dna2.prefix(upTo: dna2Index1) + dna1.suffix(from: dna1Index1)) + ) +} diff --git a/Genetic/gen.playground/playground.xcworkspace/contents.xcworkspacedata b/Genetic/gen.playground/playground.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..919434a62 --- /dev/null +++ b/Genetic/gen.playground/playground.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + From 247c308a0ae5c4c18a89f5b58be5e770a673be22 Mon Sep 17 00:00:00 2001 From: horita-yuya Date: Tue, 27 Feb 2018 20:51:41 +0900 Subject: [PATCH 011/271] :tada: Add Myers Difference Algorithm directory and playground --- .../MyersDifferenceAlgorithm.playground/Contents.swift | 5 +++++ .../contents.xcplayground | 4 ++++ .../timeline.xctimeline | 6 ++++++ swift-algorithm-club.xcworkspace/contents.xcworkspacedata | 7 +++++++ 4 files changed, 22 insertions(+) create mode 100644 Myers Difference Algorithm/MyersDifferenceAlgorithm.playground/Contents.swift create mode 100644 Myers Difference Algorithm/MyersDifferenceAlgorithm.playground/contents.xcplayground create mode 100644 Myers Difference Algorithm/MyersDifferenceAlgorithm.playground/timeline.xctimeline diff --git a/Myers Difference Algorithm/MyersDifferenceAlgorithm.playground/Contents.swift b/Myers Difference Algorithm/MyersDifferenceAlgorithm.playground/Contents.swift new file mode 100644 index 000000000..c9a67424b --- /dev/null +++ b/Myers Difference Algorithm/MyersDifferenceAlgorithm.playground/Contents.swift @@ -0,0 +1,5 @@ +//: Playground - noun: a place where people can play + +import UIKit + +var str = "Hello, playground" diff --git a/Myers Difference Algorithm/MyersDifferenceAlgorithm.playground/contents.xcplayground b/Myers Difference Algorithm/MyersDifferenceAlgorithm.playground/contents.xcplayground new file mode 100644 index 000000000..5da2641c9 --- /dev/null +++ b/Myers Difference Algorithm/MyersDifferenceAlgorithm.playground/contents.xcplayground @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/Myers Difference Algorithm/MyersDifferenceAlgorithm.playground/timeline.xctimeline b/Myers Difference Algorithm/MyersDifferenceAlgorithm.playground/timeline.xctimeline new file mode 100644 index 000000000..bf468afec --- /dev/null +++ b/Myers Difference Algorithm/MyersDifferenceAlgorithm.playground/timeline.xctimeline @@ -0,0 +1,6 @@ + + + + + diff --git a/swift-algorithm-club.xcworkspace/contents.xcworkspacedata b/swift-algorithm-club.xcworkspace/contents.xcworkspacedata index 142713e62..5d5bf1906 100644 --- a/swift-algorithm-club.xcworkspace/contents.xcworkspacedata +++ b/swift-algorithm-club.xcworkspace/contents.xcworkspacedata @@ -51,6 +51,13 @@ + + + + From 574a19e22890585752b505f9905e2c2dbcd185b4 Mon Sep 17 00:00:00 2001 From: horita-yuya Date: Tue, 27 Feb 2018 21:54:29 +0900 Subject: [PATCH 012/271] :sparkles: Add Myers Algorithm source code --- .../Contents.swift | 21 +++++- .../Sources/MyersDifferenceAlgorithm.swift | 67 +++++++++++++++++++ .../timeline.xctimeline | 6 -- .../MyersDifferenceAlgorithm.swift | 67 +++++++++++++++++++ Myers Difference Algorithm/README.md | 2 + .../contents.xcworkspacedata | 6 ++ 6 files changed, 161 insertions(+), 8 deletions(-) create mode 100644 Myers Difference Algorithm/MyersDifferenceAlgorithm.playground/Sources/MyersDifferenceAlgorithm.swift delete mode 100644 Myers Difference Algorithm/MyersDifferenceAlgorithm.playground/timeline.xctimeline create mode 100644 Myers Difference Algorithm/MyersDifferenceAlgorithm.swift create mode 100644 Myers Difference Algorithm/README.md diff --git a/Myers Difference Algorithm/MyersDifferenceAlgorithm.playground/Contents.swift b/Myers Difference Algorithm/MyersDifferenceAlgorithm.playground/Contents.swift index c9a67424b..113487acc 100644 --- a/Myers Difference Algorithm/MyersDifferenceAlgorithm.playground/Contents.swift +++ b/Myers Difference Algorithm/MyersDifferenceAlgorithm.playground/Contents.swift @@ -1,5 +1,22 @@ //: Playground - noun: a place where people can play +import Foundation -import UIKit +let shortestEditDistance: ([String], [String]) -> Int = MyersDifferenceAlgorithm.calculateShortestEditDistance(from:to:) -var str = "Hello, playground" +/*** + All elements are same, so any scripts do not need. + So, the edit distance is 0 + ***/ +shortestEditDistance(["1", "2", "3"], ["1", "2", "3"]) + +/*** + Last element "3" should be inserted. + So, the edit distance is 1 + ***/ +shortestEditDistance(["1", "2"], ["1", "2", "3"]) + +/*** + First, remove "1", then insert "1" after "2". + So, the edit distance is 2 +***/ +shortestEditDistance(["1", "2", "3"], ["2", "1", "3"]) diff --git a/Myers Difference Algorithm/MyersDifferenceAlgorithm.playground/Sources/MyersDifferenceAlgorithm.swift b/Myers Difference Algorithm/MyersDifferenceAlgorithm.playground/Sources/MyersDifferenceAlgorithm.swift new file mode 100644 index 000000000..aedbf3e71 --- /dev/null +++ b/Myers Difference Algorithm/MyersDifferenceAlgorithm.playground/Sources/MyersDifferenceAlgorithm.swift @@ -0,0 +1,67 @@ +// +// MyersDifferenceAlgorithm.swift +// +// Created by Yuya Horita on 2018/02/27. +// Copyright © 2018年 hy. All rights reserved. +// + +import Foundation + +public struct MyersDifferenceAlgorithm { + public static func calculateShortestEditDistance(from fromArray: Array, to toArray: Array) -> Int { + let fromCount = fromArray.count + let toCount = toArray.count + let totalCount = toCount + fromCount + var furthestReaching = Array(repeating: 0, count: 2 * totalCount + 1) + + let isReachedAtSink: (Int, Int) -> Bool = { x, y in + return x == fromCount && y == toCount + } + + let snake: (Int, Int, Int) -> Int = { x, D, k in + var _x = x + while _x < fromCount && _x - k < toCount && fromArray[_x] == toArray[_x - k] { + _x += 1 + } + return _x + } + + for D in 0...totalCount { + for k in stride(from: -D, through: D, by: 2) { + let index = k + totalCount + + // (x, D, k) => the x position on the k_line where the number of scripts is D + // scripts means insertion or deletion + var x = 0 + if D == 0 { } + // k == -D, D will be the boundary k_line + // when k == -D, moving right on the Edit Graph(is delete script) from k - 1_line where D - 1 is unavailable. + // when k == D, moving bottom on the Edit Graph(is insert script) from k + 1_line where D - 1 is unavailable. + // furthestReaching x position has higher calculating priority. (x, D - 1, k - 1), (x, D - 1, k + 1) + else if k == -D || k != D && furthestReaching[index - 1] < furthestReaching[index + 1] { + // Getting initial x position + // ,using the furthestReaching X position on the k + 1_line where D - 1 + // ,meaning get (x, D, k) by (x, D - 1, k + 1) + moving bottom + snake + // this moving bottom on the edit graph is compatible with insert script + x = furthestReaching[index + 1] + } else { + // Getting initial x position + // ,using the futrhest X position on the k - 1_line where D - 1 + // ,meaning get (x, D, k) by (x, D - 1, k - 1) + moving right + snake + // this moving right on the edit graph is compatible with delete script + x = furthestReaching[index - 1] + 1 + } + + // snake + // diagonal moving can be performed with 0 cost. + // `same` script is needed ? + let _x = snake(x, D, k) + + if isReachedAtSink(_x, _x - k) { return D } + furthestReaching[index] = _x + } + } + + fatalError("Never comes here") + } +} diff --git a/Myers Difference Algorithm/MyersDifferenceAlgorithm.playground/timeline.xctimeline b/Myers Difference Algorithm/MyersDifferenceAlgorithm.playground/timeline.xctimeline deleted file mode 100644 index bf468afec..000000000 --- a/Myers Difference Algorithm/MyersDifferenceAlgorithm.playground/timeline.xctimeline +++ /dev/null @@ -1,6 +0,0 @@ - - - - - diff --git a/Myers Difference Algorithm/MyersDifferenceAlgorithm.swift b/Myers Difference Algorithm/MyersDifferenceAlgorithm.swift new file mode 100644 index 000000000..aedbf3e71 --- /dev/null +++ b/Myers Difference Algorithm/MyersDifferenceAlgorithm.swift @@ -0,0 +1,67 @@ +// +// MyersDifferenceAlgorithm.swift +// +// Created by Yuya Horita on 2018/02/27. +// Copyright © 2018年 hy. All rights reserved. +// + +import Foundation + +public struct MyersDifferenceAlgorithm { + public static func calculateShortestEditDistance(from fromArray: Array, to toArray: Array) -> Int { + let fromCount = fromArray.count + let toCount = toArray.count + let totalCount = toCount + fromCount + var furthestReaching = Array(repeating: 0, count: 2 * totalCount + 1) + + let isReachedAtSink: (Int, Int) -> Bool = { x, y in + return x == fromCount && y == toCount + } + + let snake: (Int, Int, Int) -> Int = { x, D, k in + var _x = x + while _x < fromCount && _x - k < toCount && fromArray[_x] == toArray[_x - k] { + _x += 1 + } + return _x + } + + for D in 0...totalCount { + for k in stride(from: -D, through: D, by: 2) { + let index = k + totalCount + + // (x, D, k) => the x position on the k_line where the number of scripts is D + // scripts means insertion or deletion + var x = 0 + if D == 0 { } + // k == -D, D will be the boundary k_line + // when k == -D, moving right on the Edit Graph(is delete script) from k - 1_line where D - 1 is unavailable. + // when k == D, moving bottom on the Edit Graph(is insert script) from k + 1_line where D - 1 is unavailable. + // furthestReaching x position has higher calculating priority. (x, D - 1, k - 1), (x, D - 1, k + 1) + else if k == -D || k != D && furthestReaching[index - 1] < furthestReaching[index + 1] { + // Getting initial x position + // ,using the furthestReaching X position on the k + 1_line where D - 1 + // ,meaning get (x, D, k) by (x, D - 1, k + 1) + moving bottom + snake + // this moving bottom on the edit graph is compatible with insert script + x = furthestReaching[index + 1] + } else { + // Getting initial x position + // ,using the futrhest X position on the k - 1_line where D - 1 + // ,meaning get (x, D, k) by (x, D - 1, k - 1) + moving right + snake + // this moving right on the edit graph is compatible with delete script + x = furthestReaching[index - 1] + 1 + } + + // snake + // diagonal moving can be performed with 0 cost. + // `same` script is needed ? + let _x = snake(x, D, k) + + if isReachedAtSink(_x, _x - k) { return D } + furthestReaching[index] = _x + } + } + + fatalError("Never comes here") + } +} diff --git a/Myers Difference Algorithm/README.md b/Myers Difference Algorithm/README.md new file mode 100644 index 000000000..def447593 --- /dev/null +++ b/Myers Difference Algorithm/README.md @@ -0,0 +1,2 @@ +# Myers Difference Algorithm + diff --git a/swift-algorithm-club.xcworkspace/contents.xcworkspacedata b/swift-algorithm-club.xcworkspace/contents.xcworkspacedata index 5d5bf1906..5b8dd996f 100644 --- a/swift-algorithm-club.xcworkspace/contents.xcworkspacedata +++ b/swift-algorithm-club.xcworkspace/contents.xcworkspacedata @@ -54,9 +54,15 @@ + + + + Date: Tue, 27 Feb 2018 22:11:02 +0900 Subject: [PATCH 013/271] :sparkles: EditGraph Images were added --- .../Images/EditGraph.png | Bin 0 -> 193070 bytes .../Images/EditGraph_k_move.png | Bin 0 -> 206377 bytes .../contents.xcworkspacedata | 7 +++++++ 3 files changed, 7 insertions(+) create mode 100644 Myers Difference Algorithm/Images/EditGraph.png create mode 100644 Myers Difference Algorithm/Images/EditGraph_k_move.png diff --git a/Myers Difference Algorithm/Images/EditGraph.png b/Myers Difference Algorithm/Images/EditGraph.png new file mode 100644 index 0000000000000000000000000000000000000000..f31bb50a3e8614ed7a6da5eb363f21691ba469e4 GIT binary patch literal 193070 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

*_zw=cDG{_XK z?|QTDj6MIRWX-8NXCdKz0QI7%<}#R0+DPrbzKh%qL{VJaO8f}kf2Oy>QHjt3P569p z+kPUGV~Ybp=FT#>ch%G*c0UhjX~k}5`X)}k4jNwHW*}`#; z^h*td&X+dnxGHo?-{1cBt#Py_5alkFR$j@Tvb)h%pKZY~V8}eq^VYIQGr1{-2D7Da zo~pU140?gdl_8KTQWfMbm3Y8=+H4};z@}4NQt>ok{8=e;-%6B&{*#V+$dBxTf*#$( zjvs02S4vnlptC|kMaL1OP(Wgmv*58w7IWRXrF-rGQs>d=PPrfW{=L=atC%4=7!E%u z#S?IlUNZN1D$JmPGB}(-ctzjYAC$8DoNNm$$Hp5tQ@$sgeZW$E{P_JIwfzp1H?y|T z8{Xt_y4%TyKOe;SWMdm)+2p(&6*Al8IgaN5<#RiKkKF_~!44 z<_H%WI;61;;@KZ>e|?)F1pbZ{wR9aHId7xp z7ZL4fJ-Ui@?e_Buv+tcUWRFZEX2EB3bLfxliU*|C`vwOk2;+Fxl=;zKM$(meYG`e4 z{?(y8y-)1ekE&7H;rf!iDNu98by(=RYBPR~&1g{)v7U2QQr9=gG7~d91+D5b+*=?yyiE z>Q(m|26}yHarqi1XN0l{UnrJ$7H4fN!`gQ*c}b3-jWJ8HJ~J7qaj>{>Vty$%meQ^s zIYig-?P4seg%LRe*s--g+Dc?CTYIBSI0C#uXHPX$)NuJi2gw2 zeYLMb5W;i8*VmUq-X3{1SoLCXn4~Yq?f7m_(GKu+ZBGn~AQPOOo7e!)lPbrJUGD+L za_Xn!###l@56cHMsSolDpd3y)FlA8R0{@JR3L&MdJND~u->Y~Oc|9)T$r0D%P7`=a zWy}%w#?bZzs>(jJmt(@_EY$x(sF20t+UsNSqf;gtB7@<(%NGgW0fl%B^)`} z%VoZ#K15d?r1GTEZHn9;W#QQU-zMIq7+AAxFU(>&J?GSwTd+I7_)D)XaC*hjUN3V^ z_L#e+x*`y*rKl);NEc)$QrMXAT!J{FGw&0s7^!jzYRM2~^B1?Gy~oXo?6U>;byB_g zk$)Hq%rvu1#zPxfckdVsL>xa#xc^mdAmaXzN=KcGD&wMXQgO1Ud16FEKiF`op^4f( z1w?_*204NQ9G~gL_y_Dfe=is$^O0z87WL6R=pvB_;T6KG+#W_`isfQUu~N1L*Zi(E zZ10-f0qf39S(m3y9*JHt-}&SnDcTRVJ6)_YEV$kDiepLO0LmXvx{KAx8A*Zg9`G0`0rq3?Ymct5ZZyHqIXYl`wH;OXZBo`?La zUZ6XLX2BNu46G-4ZfStuL?dDGEQLXMu=1y!d!1~eDf9DD`2tudtoMc>rZ-Z>(`i_# zqR38e+w0_RFB^C&Qn7)~`}K+dYV?6~Z=9Xm$#oKjuoH>HK3$#Y>pw|18gu+~Tt7LT z+AcpbR{I<*TT?mgBYTcu$;HvdoFhFB@?-@k9ND|NFNmH;d@DlNa$1=m`9wAqx#YEw zH+@4>k&WPtw=usoD&Cx*5JhAiA+G_HkEKg!gf*)?kFn(qKA0%3OWV})Ton5d`>Dna zD=_@#?1^^Qg|dLdUTOd7+akD+Qd#5QGfWCVlQ~Rx!RH(fz|_g`b)~yW;E!AT-ow7D z{U?<6dVxN(OA9{!*<`y-ci$9bWs|*mnOWleBU|q40jrtaLGKMFyDUY3xGq7L=5r<7 z<{s9=U@vL!mNr4DIZ82KZ`Nm`2IlUz#u692L}pNLgJu9(=3~YToLZ;* z2yOe6=?8D>5oFm8c+F1D5S{OG$0U5eM!bS1x>NhU3m6n*#P2r;GrvqBfEG4yhbXz5 zvfY_+a~F=MCC6R(vYizx^y6iat?iu4cTX{AI!8h!lq$Up%B;eLHfB4z0T=`6XsR`!( zcXpef6BFn5JeTsfxSreSMojp{7pT#Z8^KGoXx*f(hZ6Ib_n(u3Sf;vA^PNSwYd4Fj zu>LB6*xx}3bVZ@mDP~wyy>5)(wrBsJB~UuL1ZtyL%HL~akY{lGNWt3#813O?x%4$- zjJ?Y@f}XX}T|GYf=4b!)q0KFHgE;Bb@F(d(`O&j0<6xCg@^a;^Ug_AZdzHI2eMx)Q zPi0}nN(0GHXcY8o6#>CV+vPU9Ly20J4JEFqSj>|2xpRDCo);(MOf5`@X!B_&Eme67 zXL^O+%fapoO-sHV;F^X z5eM!uUp>E8<$k6}U@E!Dmhzov-24sE5m&Bg_5r$Dod6uXTl1huh=Y1Z32R8T1*zTs z`e|&^GYQ%X*1@;#j4xzjrFSK|NAD&{i4R0{*CiW2%w3To_e}CA*$VG&C^goD?D>~f zuk=eQblvhQT9z*86x}U1Tx`>oHTq^0gx?DgxapA>fcdtTs98>j8OP4+Jk$eZ!7k!P zGJ?!noCdFa8Sb%FEIBiUyH@Ntdu03+ZE+?f@LGEhf`LiR3vI7mccac+d-tm^hmc8_LQE$7x8=J&bYB>YI}xzu2ImD;nUhZp%P`A;~_E z1YWOmSCaNaE2cXrP4F?Xt)JRXeNCH)ab&H(ptn-;?&)W_IjAD57T7&_Ii>9zlxtuf z5ZRgdGlJ!X_t1I&hiTfaX(a{dGdcJs#2XGuAJu;-tHzg~1GtOVBFi<|c<3udgR0;> z;;81ep1}C>>(!r8oU8AQK4AsvsOku3&n!_Go9Te7pW?$Y>$?;K)LYjsej?w{t&@^# zD8JYH8;BhfCbdl>A5H1!m|m`gq})4b`ns3vS>}_Myq^78I`4zn7|*K@Wgj1MV9CRf z!*?P{D$%Gs=E$3wA)1?B$e=K+f}Gk1xzX?J1-@Wum*2lwd?RK%&Uy0tb%ILe_g@5p zP(b&A&vLA0`5*8*E?E)iymxc_K{koMt|wYaoj$6i7Zt-p$<@DWE;nqpF+@H?ZqjH~1mr3z1rr(AWv%^k9Ob|x& zvFr^J$sIH%Do!IMb!HoIC8?l!mHF?8*x8p^Vzkyx}}>H#RqUX zqSk!guE-o1oG9HI6O9X3a`h{pWvDBv z0{v?Sy6_|v00cAiR;SO(Hv^b~pq;n#(3Wky^1=l63n+$EFqUuiEdA9p*C-%@$coRA z3eB79^G%Kk6~*Dy9sKC$cL(*!6k+frZ3BvOekD%yV5+e8{Lk68U*E4DlPUV0W^?%A zeJ-^JE*7rX3v~hw7h1%MDRwTJ$D0E2=d;eeCd1eu|M0MvsEr*ekvV_t5{KBH;uI9k z!mPz5771PCMv1iGPBZq~+C=-avl9}7aQFQ-;{N1F5=Yz^-NON1-6f8UBXk3L-~*_i zwf-xYleMZPLZhTE7=)yC=YRUfw*9N|Mv9~T&-eFCK6gZ2n{Mlw!X9vlN{H-1?Q-Y*jrD8+v%;A~B?u^C(G}R% zvfrdVG9=8No>BsxZv1U_8H1#e{tAZXC1QF}x>_(K>;7}}qlxV>nUoz|?=9Et+x+fs z$ufV)yz#j)d-Z72uVfa71;auMm*{67#m8Z#w&jP8-wz4uUB~#sjJEr~OZx6+Ct-@P zn7v^T_Y3}(04;k*cA^E|z%gyz{h`r##+6{vme0z~&N|Fk(NI4`2iJHS{Gi?;85Eso z$vyHk|AD^AMUE9+ua;(#Y>eqV#=kSS0dB-m>+<)j(bGw97%XUQFa`&Y$xU`TZK8Yl zSl(p6Swbwdy8*gUR02Yv-7iLDpJ|vS`f>u&rQKuuFS#<-+K6LdceOB!%MiXmqcUpb zj69g)^m;9roJJk%vA1rX-xbRmtz69hzKawAL7}gAjrYXykwl{*Oi6vT$ zE?~&RpanO8O!aBYcUmW})+>ZVD~5l5rxa?JWs~+3nKdjk-#W$%K-zn4@6P({`6!R$ zh#aBO(sfMoCHID5A{?T|y6BnY5Y?ZQW(%Vzf~^E4c@f?4Pes@kOUe!;tXox*HTnc? zHy2R(ip;q7TFMTF4lg{*%xd-=zg-4y>bXy|l9mS|^_W2wo4T?eD7AuYk@ZJ!CY=a) z0+RafqDYXyqi$j z{zSDpaiIHpwoUNO79ANmnooav@mg9#9zQl@u1)Jr2=`}z3<3V&*<>GZP7yAu$KgL3 zvnl?%tmPl^i$xo)z@0V~!QI810?vTlkeakkuzf=@iYVb00$cHj$dpKq$WC5Zp}{2> zaj^txJQ3|CKm^5sm3z|`Ad&oEZoNQTaq`!QX3vYbXF7b3mP(v~qN2n-5~GtgrH0eP ze|$hpGM{z>NB)K)mZW5-H(+Vz;K5y;fK$RN{&^EP1^6k8WK)kGK|dXc!oIkz6gbC( zqbjnyGu?s9ofSt&BJn~Kx2ieQo6OC)eR~wY z)IYJN(e!28SB7@3_dgaQZb_xxnjB$LY4o_mxZ?-`@W4BlkveL8XbD|3`JL z7TYyEAaqM-Ga%$qTnA4E6@SV7 zM5YXgR$WcL>SNGt7lbo^6qzCE`uI$}MtmUhFH$MY2GBz~>jh!M2^1~HoP-j$jP$A# zIf|HQm}qFx(p`RGHZxuE?a4F>ewOx;{oBr>usqj^$ zB{?5Kx|7kZChFubR_S=AA{oh)NNijPSK#Qou!mXxWhvz$ksYJ|EPn$%Np)*Ic@e8@ zENQkR{G#cPAHsYf+YTlLmxIC{ZU`QRT&_Xs-lHb62*%!94sd*7qeqEVa+&cDF3HUh zrEEgU7`5OfE4p`I0O8Z$c`n1upo@|f6ax_IhezDBjdn@;x`#S@W!Ek3BWb6yMVjj*$F(cb7zQKL z*h`r=LZBA6(;Adg!?ix`BffvB^>K10dF29$k?Z}Nl8mIn<4tI%UO7%V&O&j)7xzcr zA1@_%U6jO*FTYOkOEOYE7d`N%R=7Gs`bX`b!~i)66dDwd24k->tH1EP%G`H-0#l|NXs_tN+-^BW%!PGgZL+e)`<@dCYN?#~?kDYE zc1mTJguy^*QAc#NFc8TpYq5E>tC_3Sp zAsO{Kd$fMg>%jO9Zs(EXhRiJAhGV-40>z&BTX4N!BYDg%M0ns;3lMXTl-zOdgXq-Apn}_`nB-LGfp2XSZuc=%MVQN zoSA!l0jAw3V$ynM1Z0qWQp*HI3BDs@+K(6OSmg>-*u7ieKGiR+^@@{YVF!#UWkABn z%2cgSxT}N*!yjVjLIo{#Q4WP?!dxsvqH(E;n)}b!($rnrgy8}yaTKg82c~HjeG}rx z_k_5lv86igRlKNAx?Bo-Pgd?3rUiTx=2 zc%zN)3??L-V$8e{Bo8&dBOl#!nun{cxDF^d#{WPTs6HA(-}OSWzz@;|Dxdu?Xy>{I zTTztnSQqgXr&v_8ZGHcoxebG7T?WpxrSa7b^d(JT`dHmac3E%^Bjla}&P~i0s~&Ow z5gH4uYaZ$*b11>At#E|?Yhq3Hfk@(juU6;**gYV_bg8XNJ2LG+ADPPaxFZ$DOM1pP zN)Oo08+FVuf_%?@!$mohSN1em>$_331->we;ZNq>eH|VVjnOIAU_rDvOi@RJHa`!l zjd5Q`=tr;Er!G$L+s{tVIdUjo4nT9fM8Fu(Lp${(9|p7LXvH`iJFw14db$Q1uH|8K z6VJU5N^(SxU%M>RdRGT?g3uBSeEBEnJ7WIqrk|i~)G2y~$aYyESe=%s7upo8$P|Wm z{_+06vfvk`peY3)oy@}(xYX+gDQwC&^l$gt(lJbE6t{MV+NIu4;+3_(t(okG>!O+_ z(@PJ*SRa^OjFA{@?5Rt})t7T(cgh*b@TreVM&>=1nGcA+@@i`TE8!p#ZUaR8lm76Z zfAimN11#Xj5<@4#h0FkVCY4WZ5l zm%=)rPWHkK*<9xq14+P31TvvR`t85*3X8%4^0NK_hD*rAux1c^JPG+NjG*Y;Ym$O9odYw#dM|NHVw;CLp@DAEHcG{fm(juTp%vq#|z3C{CsH68r*a6 zgh@cxF5<7k{R!Ib-}#FSnU##Dw324zzmRLV;S;KMxZb}dL(7FoX4f@AOTq5K?MCq< zbzqvG=lAE_9J~;2bp3LP-$zip&tbBa?%txV_={9`J6=-&Q+f>TUwI0+@>N8F&Et+p zE~T0-X;|14Ua3x8U`A zg9?J_?Pu2F5)&2C1C1(h3`*W_5T5v>ItN`W4_w&A4_A{IueFk>2!7fJnCQTOqbQ+y zW1<}h(8ByEYl&%x+2a1l5ZLF88W7|kqlxMr5~=Z}g)X`pfIvoyG-gGCc}A(_Up zjR+#TdKTidg(J+L^N3aVjy%zWT-dQCe|v-m@K#-hu_(`ycrzuxttH&bc7GUbb}~Dy zasG8X|1;avBiq87fhA%F6e-QGl;HW|$sdVDeN_3Akd|=>dcMc#xsJw#e~@_dX4hq0 ziD`RLB*Ng@^y)(Mw^gv==!2B5oh3f9mWeZ5@ua1B3gI;>jc0j zpBv$IUDM!kURJusOl*P3)CP70%P`pcKL9vSP~(9s9JDYBh&^2Ov_;WK#yAYeB6&ed zob{nM5kdfjEUG0Hy=_HT#r37v7t{`MWKFSecVy-r(Al$FWsHqdtAP=8EFYwPD z@}@ob^5#fIPEzjI3f?SJ-GrBOPx8dfx26HF34Wdx?}6<{Py74(69;7IC~U~xCjp&e z%v1T`FdtaU#LJrqWIYui(;jIcR<5fUflJAP%s{ox7y`952YE5cdaQKQf!l!wA&&9a zm-tgGxYLc)FfIA!gJ(eB%~zW5He^J5O1BLNh>RCHeebTU$2x((jmPXC-1w>a3l(xa z3L}OvRm6jPmuk7v7WQo3&+k1wCeaL=a`N&-53)_q*Wm46j z;kP;p>5uXEFH7Y)c#~9lfe{mYim}hdJ=RP zN;e@M61|e+w2O-f^Er2FnXUewSi2I9`q(f}bX1DIRbU@D^0k+D$q701F_U0pTt;X5bxX$eNTz~zNS534;7thqiH0;_-*rZNiw z?BnQ{;g6yl$>5S`E2kN)eKF%Z3sXlj47K#BDCcSh10Z)fVXJ|G;-Y;N$_tBj037{O5W zbNsz;^_@hF+PGQXD|<-1ENVSED(VdoR@X-nYX=GFTR*MlTS63W8t8|Mow2LE^hZB4 z)7&lN?Vk#_9Je3hK&^M~Fmn&`6)A4iPo%Xi?VQRSe1kTdq@6IY+2g(40BoEgaPeF4 zWs8>h=MHIhz(P;Ee*CF{G}~GD&_lGA&*p1bfZeHPCDDV=l$R0sff&eRWek+p$G9By z2PT;tIC^&Zx`LIJ)m_Ya87mLd*EWm6!YrGjKGZ)xaHM{O>nierjd=0Fg>Gx5IWUH& z_5HFqse=ur*-Ltv=d~*HWiqJa_;R%Tx^tW9xxA)ps={O!uQzz^6I zS}GsG{%9XWj5j*RF);}-{{Hm}MJ4K~@oOl9c7fU_%Y-k~ zu*|`T*zy$48=NRaiMantR)41ZLA!Z&)o-|gr2DOiXEI5RXH?+Iz$M@t%fAub_$)C8 zWP8GhFF$*-pOdnoy}EArou4|9;{!iE>o5U%%>G*!qHCPZ%dBC#O^o zeE^B({2ri#9y*MT9m}AZf2tte9eB#2^3Sm0?@xr#D%F>V%7#oC?hI8N0j5e>pD%E0 z_klDQ?&a=N3w4}(BMlk6nM?^-Y>PGugFydf#IeK@ND6oBXTki4b(q}2Smm?hQ1(jA znCGI5g~zV0?N6d(Ah}w?ki*2qCr2`5iHGp&FJ;=;;Kt&(-tZF|9$!7Uu(K4Xg{4n- z$9^MV=EIz)I$32AYWSp6lokW) z?_V#k1%Uh4AcS*i!2gf((HaUHJ$P#|Y!m|$n$*cbQ82oiANqA482+Ajc{$Kw( z{x}5Gctw-1Uo#3jEg^U1Y{s-|Y;~1acnp2Dson%zi_Jv$7@S_fBpi%sjv}dF?IugO z;plTOpGEZ1$7gCh|CMF@{TGq7O~+q{c41N#g^sZ5-UbAJ4={4SW9Wxo~qW~5x?lSV)# zEG#ogSh!MNj@wcm|9591)kGfe$HJro?gRn_x0|xLgn0A#1`OQ+7;1fY_@&$%@e=jR z#3WBVIqOYf{K7+lDzaSQ0g>f3#1cIuYW-b* zK3XFREO4@a1@XYf#NNrNQf~5Ft)o<7nQ2%2>vogZhGt6P3DGwluav^^W+M*k^2vHO zOCcYV#6VdWZn=7%@oLksFbh}Si|wKYc1E207mVD#B7bJvtAn&N0n~vA%hrX#VEiD; z*NUD@8{qS&02fDG`3k!+25mArI@BA{Z*tkItiXW?K_vsPN;c$Lf1v+U1ZWDB;6~_? z5=oV>d;5Z!4J%QycM@4OSqomD9h7_TpJhGZts)|Y%|WjC(y1eq|7?9JmlaiCXx?FI zO|84F@U@;@VrW*TMb|IR-BGK-XZLFQPDs4-RseM-iH)IX2(vfS_so-hg>gT)5||f6 zF_@Kbl_~l<&(KVoa+CH;zX65gvrAm56!ShV zPi1CdWRzx?%n-1j^`8=?(aiq(m737O;|cTtM9K;;`;nii?k|a&>P8~jjK|Bi}H5d#Qdza~0W`H_*;dh>9^7!$EHZlYE z0H`*E%EWn8b9kO^=vadkZtTR72qE4~0YTL5UgkU#vLfM@&p*5XELDs;qp$A+3E9ek zgJl!SgL_bHz489_^Md9dz`SMQz7iKT*O%o&h`~bcP%qB69o`N$yFbL&9aTr_*Cxt+ z2=MRfq+M>W?>GH3CHB}e^Hb{Z-8kUd1?%3*F@hmr13vxlFBZ*() zN3186i#g2sS2}DwP!*K{sbH?QC%}lWz%^HWx^;N*%FX+2>u2aSox?-dTnzm?#0XxN z*w|Qc(AF4NbADqjt$sa zWZ+@+h{RiFwdR9)XpPtdpj?SMt`enq4_1k6FX+21X>5P0H0$L*mwn4_*p&J3{S#$K zbF*wMnytv=gz_Uk^=?px*eYBWtv_$s-f0a>83_`@UXlQsC z3_~g2L5=+ZXg*ee=v|?v-g^ADR#_FRiE-mhd8B^Bbxf+}wU0G-dkMLU$H2xFnT4Kd z`OV+auX5a$9W?_!@-xhphKtXfKx5jzvf}9Ir~y(O@nQ)f6w>ky3Z)-_q9pXE=JmI% zVtt9qxS)aUwy!i^qS8wwAp1MDejMV5i z?xez+B|c2b4L2xEh?qpTUv*Bu>|Ul*S2Aw$7%W}+cFasVdGO}Gn@RY?eVuReybbF2 z7RPO6#g$3Uh3gy_@9hqy$&Qn;X(=_}vFp{8d>ozgl}B3Upyc%fDE{qpsf-(baFO@k z?SqQ@VPu|=H5Q21|rFCU|x~FIv!S6Sy<^wQ56ckzKAMd+6aOd z)Ufk9lwJNLG9$wFoPc!ZcR(>Y6KSDz%wd)S!!}!PW^1%4(tRjcY}RhPT%uv8-f{8S zjgA+^dt@S{tQtG{l+$b|%v-#4;cT2z*jR%>7YXgOF7O&x`CHFL&!W8eccD|ha_yQT zi%RB8P_hD!5fzqyr2qcO^;`P2vE4~*EEfsf)464_1=KG<4JiW+k^PtEPqu`y;TSBU z&|1)k$U}C?hYCu;7&j7`DXx-L1f||Elze5pYSq@7yPT16H!l&lx^c5?R4a_sXYSqU%{;NEP+u*{X`Z$mY&i2J`8zJq$T{&3nnstlvYz1|JYg z&BFWbFRUHP5Quj}!HCjk1U^!nfKvROF6m%!A68MooqLQM6TR==@uFkR+eh`u(KKSW zm#aB6i>^TR9=SGJENhGN*ZFZ^foyz-h$;vgJ86Geq{BjMZic9j=*vo4X{E`b$yL&Y|uy~wIi zQ%x^exYuN|-`wNKduaImk>)~KJ8J1Q%5QqA;xSGXl~6n}F|jn)`NL4zR^#he{BETC zl_jThe!Hea$d37gPABk?jX-&vBkz-^sYc6PojdB(|MQHf_~&4bt^>w}9G*BhB|VkVdJOPZbxJKuBO`L7flX>l0t$q;PG zpA@uye6VV0a#MS)Z&l?!J+4}U!2>IkVrwD3(Dkdda}ms^j*p=mT?pA8E!LLdG9U}e zpDfaQUn({_XF!6oe2XG^Br*K2=Oea!41>N1V*6keZ2k{9GVQc;B3LOLhIybL7=k^4 z?|PS!G1$O+SEdM%(VWd(t~2EEaN$CTr3Wv&-;?fZ9MoM5n=@ojhXx*wln7uN9?WIG z8}Ks0O*;1w3CUwbkqp!SR9~bfu~N`uG(Lz{!wLiue7y6@1!tpbVeae}k-^z?0% zw;F2s_@|t&nYuxIDcB?KF@4$I$rH=3i1z`p>q(A z4iCtU*pg%V?ZdOih}36vp9`i-mVKiV%DPG^fp17I>v(;ezt@-dwJ4?^@4V`|Y&2C4 zoz$~I_-Qg+=bjNOwI6{EcUpMyC|z8fLpgQsQu>HL#{Nr8=?qOw<#G0xl(j*@jTZ_3 zI(||l4J=a>CsOr(agg>t|eQ@mW5YY)eYBgFLVxXECKeg|(J%8Yt#k}Br@*|@^obh{x0?7@ZhzbrIu;hejHkdDdId#qKaMBc5HT}%9j~|V zaTi^GDd`EkE1iIuWD(;pDbJi&h(@DBhSatu6%)=YM)}w(70X)ISjgwd&$2BXQy$}? ztAHyp#g@Q#sNl%M+vA_IuUj9(N_+2+y$F5pAXefNT7&k}Z-os}*}0yIkY8-*kRLa^ znBo4o2-`gO4R=j+gd^N^j;oVR#{nC`51d<6oO?Yyg{U{H;`iQeubY#$x)i$8gkqRq znQ^Fq;N+fX_lqy6s8#cp0WB_ecG0hmbr)C@ll3sc7MoFn$OH2)>%Gj|DG?rMX)CUw zl$#pzoemx>e8yYl@wqe)6*U;6j@d|54sE6XC@MPi>Aobpm&Cbi^k4y162lvz37^j$X(jXfm=br>kD~^Vgn6Tj2_y_u7PS}8^DqByt(yXZLr=xoYkf`It5fHa-Ue`euKS2;Tr$sB z2{LVMoofexoqlry+{G_k>$A@njkMcNlW+~^OV>M+O))J_7_QtWrC)e`=8yYgap&2| zhd=LbT&~Yq?i7CB8Z!+Wlq&K=?%N$v6l~i-KW+KVMYHw zaw|fIw;G&1TL|Gh{_Z=Z2C!~&`)$Vgi(R9`1$S(gA%{GQV2ci=lFJe+c$Iye=i^Wb zEqjcjFa-iCoQLgwpM;DC9`P+t;fHR9)C5jNAAZ;<`ra$R87zXtKm;D_Hi43b&&yu% zhmAv!GqxpY!P01?uV-4q(#Y9-%xkB5Xx&t$-s@F|MZLwxU~7x+5y0I`sPQ<6-lgj+ zAx(#B+g>4IcGPhM$w)(@#6;RG3RYtfwROWv&%mG*1|ki?xnz1;5IBzp;hWJ*@nbES zzThW-{C02mRrkgb;*1?99kbk>rjeLaEJZAj(He|SIvTY*MPx1WywP&_7%G#rH>9fj zg+4(P?(k04XQ9p&)22QZ9r2EQ=}&!TUY-GH_)8&e5&L5Og5i}YYw#J2G8B9BhX zOM$fOv|UzVrZ}Jq=a2Koap9vmz0+P%xM)6b>9eX)iDiZ*v*d^U!(2j|i|uei zB?VjQ>FbvOkU9wH98(mWV)R7YfNX9eHv|@G)2ErDrfDdxc*^C@BB`^*Z*uKC_^}(6e=eG!*(|6ur>W z83uk#rsMZ)BZ7QU_!GBDg1-^!hTJ>8`dlK|tt&vxtK0xyriU7Dw#AYluYw$f(c`2c*p8d1w}DpHjV|;O=O4usmz21Id5!st8$lcyO||+< z=I7=8gRN?x!Uy@l=e9Ri`BZSL3DdNKCCI@?S6yF;!Blf7w~5CIZXI`@4t}>3ZGD$T z9Ab`C4tx-8Mx7A&u?h0*?fRaQ?<*sfS{7C2ubdbSv-RQGeSg0hdqy9uF=X?kBIIcw zIWF)i!MQ7Z1h{?{df(MZ%-aP?#}#}`l8N*O!N;&X!O3HQL{=jR*Td5k{!tOh=vn($ zFFUF6a(-1rDCc1Z?PXYq74m*zoK+mTc&uO{V7G;FZ)NKTU_q8T@(K0|*G_vu7~x?A zjOt1P=~Y6)IEIey3@zdxy&is5tsUO80({%E`a_4kL*>hB9Lg|&5aVMf`^9VGEUte} zy1GA}KsKF`*ZEQ$CXd+~UOg#3TgpdRIyMK`&8NaHG z+qYf8m}aEK*BNd~gEUN0pcE=;Ec$6_sLMQw=&x0tgy!I=;H@Prf>cP=7F~^ie|AxjlmnBHF@vZ!R7{dUA3SA-OWXD}?YcIBFRB5tF zqN+>LlGkQ4v>`quYfM(KyL4%Hj`TBcVdaS8-H`ae3y0!_l}Y6&S{wokQe1tUP4`kc zUVA#8!7@PKdViyy-^0b=q`^(YQE=EnoS8Dy(s&fsKb(S(T7<~YU-ni~=T?$6L7)&c zyEkek{B0>%fFG`*5)kE@Sy^R6i)4>p%8clrSJuRAN zC<(<}yAnB?OX(pY;!8VKMVeD@A|>ZT5^9{RQOphr(Iq4yqO>%3yH51bvZlDXSpn`M z##$yQr2T3g9UQ9Hax!;5+v~or&vwfc&#!`joxuP7j@UU=Ds*3lq2sU&0s@&ksl)8@ z7iisd_b<9un$JJIXFl68pr-)+>a)&Ng53s0^V0a?h{)HGu~TBiqxw1>y4U0vHRpTyAW zKRVNMBjoamdA@?TCjTnX%OqykFD~Tu9DQg%yrL#fX2p|;F~7aTc93`tz=DarNQQVQ z;S&dk4~kiH)lioQW7S_3oxw$!qsv2NoOwCkzg$oi{j-3{iuYdTze{p#t zn9))Q#EC(;DPr6|wqTU~#pPhM@3q>T`BY}^EClnetgIXX>ZV!tM4QQZWs5w!&ofc* z)1tgfgC%6DAZ&Rp?cXTGlZya+CBOb?K%KAEGUQns-t{WDK#zLm{92Ny2La?ire z#G%XKaXzPGutcZV`FrhqIivVa-@zv?gIz;muk2b!Fr>E%=Uh3a9SX5_e$nEiQqDgcsL*-AmNvk?8W$(2=5{8OfiWw#UOcP`nh#KMexWiY`2&@q$2XiqlhZG;OHx7`B$QI z>h<}XHoM(IjaOB4a7gIpL9&oy6h|3vN4`4-Odif}zC7yx^<(BfT!#|L$(FJ`dbIk> zY>5Uxqe@`Xys@!5h+AdtItb=3Q=al5@BdT@v4Kfx{Mq$~^ImYYD*+{(55OwMbK%JQ ztH_LW_gnkq&F)z+3iB^~-4kjhScM5+w^&O-6i0YoZmuo>5_iS{W) z`7IT4I`*j(S%z5Y0b?SO_6Xe55=!9aWOV0RZzLU$60(amwD9qf!DUPFzIl@i&CzU9 z8qQmHZ5I?aaEe!e}b_?}uKBCBY#o1q+VEf`G3DqRMP&)?|A+MzCw#k6BK z%rB@sIz)Q82|LTfak~OMr)JROx{NPEl9g5IBQPrI-fKZFT`dj2zO;<)6&4(H1i=*% z!T=a`fp_dVCB|l-g@m*3*Crn8xB^^Zm_2Z@Xl^D2_H*Fj9)h&MiD!1^kaOc7J9X>U zE#vq0LQ+JQ%jO$za>vK5_Mk7yq|-oG6Q%i>YhoM1Ew}faXTooLRII?I(yCPdvfsq_ zN0Z`*#WF529=?pbFBX{72G_UfndbpN47rs3%~Kja=SNJ-&P`vq_%5DcD~*wN@lu>% z9_wbF$`c1}S)u!0$i`L!q~fWO_*{G^3LvkZ%wzDK&8)A1b6oa7-qA+iS7pM7YT_GP z3P>{yD14^gPk<09>pg$^^=+Y42vUcP^`_;b5)#S4MLHv9SzQR))pMorjois$^;bp_Tumk!okFfxYY zD_wKgpJ&+&ju4f)2yD!~AVobpw#P>EP+hzYq60Eey>}%?&OJfIx45_%^6!n*h*2er zgP%?i8G6j-W8&iW7sc1!r$<;I8P5F)Ea20_F3)&6aiu<_x2^g2Xrc zq1X36{-ZID#O$S?@mgsF9#)(=fBQbKzJ)@YPsbac?G=O!$)E_kf&1(?g|;9U)4dxLd1odQZoM4Wct!O(8Hm( z;f`i)NsW)+cv?~NXy8AChlP)PGAZ1Pja)8Jg3^MN% z7{z;Uf3x6UA*Q->36llJMq)Y20kxV%7h8N}VG@wIOeNh$C|SPf%z4E*!-q&>{Kvvo z4!2~4lF(qpYdFEOJF$;D6X8*QvxXffLX893k<8eR7Ouo8zLa$$lsK-#kX9d|dRirA z+0L(9KDw-%Bkf3fN7Ul=khIKXpkGyz;E8|`OQa;+b9prKSG7mAif7E%RN`S`%rY^Bb5oCZ)2zbbRz|Q6M~Gd?sf*#)sqk^!`9a9 z`P`Q(RFIf0Z!;CK*jQ&;mLTEq;3?yh`7&e#*2+-Sk8+z#!WF_?p{g&@AyV=Z zviqf0@w{CD{$f1~lu$Lyl2(*NPxvF^1TNf^6E4SBQc&DqrI^yCJrrCG+W3aY8&CDh zTE%@Yjkh~rcz}c5mYH@BZmoNyJNF1=3AvgXHMmFe$r19;Wu!-MFc=}hGiyu~XyxNF z+t$3=Xvm!L$fhUF`_;AJbvf6g%ZFMBii)5>qqUc&l=HRTF&vZ!797%S-4={BKP zME2&Up?r4{dKz#2#9<37!J%}FhA0JzntWYULRgJ!@W(Th)tsyrOARe<+)$y$sAPkX zRT`XN@31wOc@C!p_rtXuwt%v*RZPpMvnlcSZ z_?Ro2S8f&Iqj|F>M#*LEE4|np#Pmhq^98|OiE-;KbzhJ@Jnhrn72+&wQvx&DjQJ=<)uCiWji>cpPdc9E}f^h{ZPCNYWS zy=;IGArs-;=7xK1p1U2lvVv^w0nlQyklGBWah;aVl|S(@WnE>@8}QL^6~Sup8)nfmy%c-8hGGJ7#%J~Ms-XBRFz8-3N+J? z9}5yuFN0h{8xV|}!ZsDgyg6#2O3;ax#(xt(N0U>3vENVbSTLTsPCzV9P@L`5rDSbx z^K-2goG1+*Bs(KR)AeF`juC+zzX*EzA{GkQ{Uk71OlZ4BZX&~P<^ufuc*qr9A-?Gy zz{(nd8ApcC_bsmHE1egH)WqjF?_81wL|3i2e-^X^rJxqlQ}mxtnU@J z%uN0S9UYxva5t>byCWKD?%X1SkAd&d~CmVI`-)v57-j(O& z<$bMKzNUah7LQl=u87luaDqy^QF_P80TnHfvYVykKlzNpp%{kql>-tgZzBY$1f(^2 zyQ#s(EjmNuG!YC93Zlh zuMcEXeil6279f>0|M=9?R_DctcY+|%@1s8;r|A7bYShwu;qqmET!G5Oj{AZJV`N3| ziz|g>`!7!!4;030yqb8*xmUQ8ETKY7sEmYj8j~2>ETN7PcOipp4IsRj-#`q6UBNCh z;&?RB8UUtZOQK@E<5K^N{OG|GJjD`PRU@aSiE;?itf5Ailk8oNS zD;|`WGY;tF2^nDqZYx`GZUW#v^uac~=JXSU!3tTFw5g@yav@jwa;N){n#3Kw z>Ob<#3e9>Z9Uy{1$nktaZ6n?}f|+*v4Zd4TChRJKQu*rPHktFz@lbx^!7yP(M`Emn zIj7#RI;oy1SSspK(`1BTHM1mN^%?FF^4BiJa6pWa1ENQ>prJuV1k^`a_c3wn28USF z5EydX`*F7b zL>BWNeLk%ks6T1;Qa^uwWznQ)dPbO`!mK z8=><7W_RC5d{oO?fSm~@%eRF+KefJAR9=O>pqg`!@d-4l%9n@B&C-vb8S#8Fao(@$ z8mS-nI5)!J27zY)X*>WZN%7kPwek;h)j-^&vzN%T-=U(9u2&YP0xwwM>q3EwkB6SraQ&%fn^-Kbvxa%nAVNo zqmcxtJCYFQ{s`RM$9C`_ZoI|7{S&SMO&8AK9wQf5P2S@-G?=UrzTZI5NR&LWD?sB} zrgx_phIr4I7oSFN6P;2@G#st5`}yWMP%lJ;ke0s9CngDNb4BN0TtX|nP$+hC-8YTL zc>>)mKAwJ0*s?m?2c*u1W2bpGT7koUb`qgEh7tKu}4rb(qQ*M@C*r~5mKTYhFzdGxI(v7FCX{_bn)3RqFik8dwq1A zz<|lcw&12?(r*&ef4s{#!eT>XvTKEc}-hCLrS zufT{y*Yt|V!@}+=;z4)c!xrg@DuEd?bn-A5!`L9vw9-`I2Z_WD=KQMfou5f6!PZ5u z_O3kqZ$)qwUuhq_>0C%w49{#5H)i^F(p9!FTs;^}8Ln1DRiD5zo)6j$X5!|S{95lE zR{QQmy8u2$ta$eg;DZQOEIVh2>RXD|L?WdOBRt^OrH)f{yKx^jUH2{OscO=JlcX0$w+2+ zP^tYaqzJvN=}?8mM_2BaUFFP4lM#Qw9;;SSxjU#p9-%=4iS_^?-HGT3agPiV zD9{bzrekLagT2!GgGyCrChGi8ObM+P#b3xFzx)H_5lB7;90K^*IDe~6;DMb+??@1< zj>|uZ3?{{)^xnT%z>_t3UY%njA4fXT{l)rW$9G-B+Id1H;BN3-o5$Z@epwWRW%2O?-Ibw3FJOWJC z0p%=!KCWPE?zi?)(L_pC);y`z6XfCH%(^$^l`I&@`cT7#ao_Rz1&winkKDVKoeR5$ zA=dq=Gw5Pia?wA=#E6T+jLa!3y3*n*+`C>m7oml8)Sv&rYxxTrsuSZBE)h=r(czX= zX3PVod0HGS-OnDPtcVClXnTm%<2T9o!Tw|jB+!`@pgGh6C80%1&9i93I~IK9snhsq z=UPJ?EKz~n+=v)H#*D9SO@6EJeeXX%WIG+Og&l2~6^Gi16V~M}A5A?GiW5gbs~;J6 ze~}xA0mlHUw5=?4|4_RHB2dvj%a7Rd*9j)W15Qhw$`^zLSBua;a=hj(T)N^-etn1D z!M$X&It@m{NK1K$~pwEw8A6KB;WT z&eeolx5#T981+lct{lIC&b^88p-C9d*ukHEpW`*jg^w9NzBX+OzsfCS6Dyc^?D`M2 z654P1w6!1ufL0PZ#P@f}bqL~A$S>HC>gwtuoAO!U#&JZw0)2$&x{)4spnlT7h{0*m zz98w<)eUj!lE*15pK$5Y9eh7=Zi&}f+weJYj+b?h?+$AyK96mV20rR0d{j?NNF&s0 z>$HR_;;wwLU%p({gI;eG38kA^QG8S3e?9UI+5|Ir?5 z(P$tMyM++F79q$_9(7qzgE51o=dy1h*==GT`%QdI3|4xAe+!GFA;^Kg+qxdCMqMD# zi#0mPVKrb7ZquYjx!(OiNF)vUFL!r$Z@X%gTNjZXb?)761XBHTtJY^genw7FJs_wX-;=rG0{WgzfZ(##gWzB#XaGbeFp131(R?=2Vtje>Zp)b^?AN7iM-Ewg znt*#3&TyOmy^jh0A)9-V6WU~MLE2OTqb>@5etjo)=L3{^qMWA3;6OaF2cBlBTIe1g zPRr?D(0(CoMq^;#H+q~cpDc{)=-kU_3|HEgpKOrLf)?3ntyUV+)W$mCl+04ETx7_> zvw6{sA`-AIAl4<`Rfe==VD6gZ33xQGCwgM|Xp7@l^5Cm`SJw=jzZGkr%9IwQcr zJ@2>=G<;s4UsAKH2Fv~dbLKLrG)=Bv6+fe+qpw9st3MQ@$*u(jz8Vu!!hz+PZDlk3 zCrqrYLZhCM4tY~FTeGA+16sBjI|Da8A8`FhEnoRimpJ+R%KMQ@vr3>Fg*|b4yNZvI z&KtE30+$}wiAPuF8R~*MY%lk(`;g@rCuaE$U}@hcw+Rgtp^Yx*g7Y&{N3FcNqp!}#bKQRRlmi_m^ z_#==9%imlr&i|4804|GomcU8=0<~oT`=|=fgeGb*?)`)jiFH9zi1bP_ATTi@fkE;J z=^@o*uYD*)Pt#wh0)*alPNv7orHk%umK!S6SU;BXWfW)*Kts`-)@@(T0MMLb8_Y)N z*?j+(VD}e^5;p1b7Fwk<{ti9 z^8)kgj0zQTaRYwmTv^w7TSuiCYTOc)LfkjNz;VFJMkprULPkw}!&gTu&4l7I_AcEN z+;Vj9%_$-i)5h5XvJ(2+y1{=7TXRfqoQmi@(lhjRpf(#oo;;P=PtPRljW~IUq6`i`6b7Tit?Q^NS1djEwp7tGB!p>hB9ti&bWExYCQWd{}6B1%jBa|vn{W!+?- zu^l@|Bo4hb$3uQusQ$_u7WR`)R00A5@rkX?Jd&p`K#BWZp2LfjR-aVkeNlX7CKLQF z9q@}36ONz1oWw`pE~#5n zmMuae-0lDiS~A9$SdvH z>f>c z@hXHB=U5*G!w?B-^dFDuCwFAHjxjj%)41zu1@wK~GB6R_brMWLC5BfbD zjUhSK>!(l0$Vz&SW0$bEr5;+&!v;2L;$S*jxIBM1xONp}2XyH37@WsTQd~B6IwTkA z7V)j7VpK)1eF>j}v4G47()KHg{Zg!;ERpMNw?eX9l&O|{A)4BLvQ%^n>%nlgnULs| z0GuowG38T@j&npG8@`%&L59hECeWNyXbtEpbMDO8nYg&JLV8k*PDDOS3K_q^H+$;! zv#($bp>RcTv`CVnh13?2*c)GyP0vn*@JZr?b1!mI-73^R^V}D9iEVAVcBPopt=>16 zBw#~bGzgtnI`vah)}G&EW(v}W;$5!aaNpn2gbvID|J6y6zTj02#^CfOr#5`F+~)`7 zqxhHtznb&%dxc|39MzXr zm)dCVXY8=O$@_9%ITg`g%}YKCT)hoIVo;q``9pk+p`BdC4uF#Ly+;7jWdcgQq76PC zNj}wmG_plx7As?DRV!fgoTtGpof&(!4JGdMc&87Y7ZHTee7Y;UTQye87;5a^M>`fBF^!=8 zzsS4Q>DHq=00ijKY`mw_3!TBpwYFb2>TVlHmMY@E2Mp>MAlq~xG_}bbZ&LmD7Wh!a zi##&wai2CkvQaXq%J?oZUd2#*Jtt6YCLG+re<=Nf59U>}PWK&!3^eKO3qEOSlj_9B za8cP)w14@_0B2_lzKV~*nAcno+OnG-U%sL!Tf};PWeiT+bw{!{*bX#u+B7rg_{ev$ zJiNS-+Nl^EfRrT&phWMZQr=PkINVn0O89i%WvIQWU|^-K-W(iyh5@a&4KfZ|<*&(K zf0}~Mm(s%f{Hc8$>7`f<711A~la^;8tAFWs96tuMqIlbbO(jLZHcAhEZ<1MCq%0K1 zbJ8n*BVFn=ncI1F-la>(Amtf4)c7Bz*#Z*pThco1=u+Pm(_PO4Bq)p=g3FyA-O+hVZ6eT{OR10>`$*vDE_~z47*n zCw)$us^-fnsOvV~4jzXB<_E0xuYBe;5TW7Yq4x44dWdcMPe5$yU)XKf1LJUwJYSSV z-oKE{OpeEW2-8mg;I-!KmqloiZigHbe6;IQna8o5v{SMV*lwy-xGoJ!!4J?PKS0QE z4GJ;*UHE~m1&*t$pkkK=rSBf>_ROkpV>SA4BR^0H`YF8F2$hnae$H4OWw4a|O&O$8 z@|ENLm&`UGxYVh#^XLf`uAiN4^SdVZh{}!&P;Pmg0nJ-{OCA87@+AYP!<2}}D)vA) zlnO2##AQ#|<=l*stP#QJ8Ykfg#4>g&$bzNRQyvMx4{XZu{!1qOfcbB92l#=Dhkw}) z%5c!zHajgKV<#pDrU*elyW9o{I0wOIOTz6rOw#QU-iNX~*{$7zTFK(6l^v}a|Eprc zdl@^s$!TYpe~uI4`WY$N#3M16Z$(`^rNQXat3~RLC%eN-QBMdJ2g0gTP47e+=H18- zNR8ykZo$4DhHI&JX%8$6aNqpupiLHV{Jq*u%$NA~d%F7^uCM$Ae=Fp-c}MMVO=+Fc zV=Bd8oMU3kh)amMTR2aDMMSAOO{Ly0z6iChY%hFmnIjrgN}E1Ms>yhh@9qoi7PgF* zo(e^%0~pPx!MV6i9v(7ef6iFWhrjl`SQQNj4A z;6gx6b0;Dz4gl|w^%OYX&fr1GefId8^^?D|9xsbb1 zr%!IE2Cf(G5|wDiQsgKQsk%g&Z0a50ChIOdO+l#d2eF0#P9ao4CVKkx-r5q~eb4bX!X z6oU;Q!d_1T8z3KQ!haZ+bg~Euah{CFRvvC*z1NDrip;J|TXCxfXOdDKl0NZFd) zMho*nHmhB6f#i^XbtdpL^&UVCOc(y1CP7>=&;?DcgV{sF*NFGNess_)mtDX}1c-jE z#HzkdV%eN_KQH-hC{+V)AwbUy^fHCh9r!tnXlc?1A=DPmx^2=sX6G2A0#bH;H}X`XxL*2 z=ozRZ88fxOEp69N^1IQ{AzUhDP`Qen+MvwexZOAOXm^5bbL8lpV%-Ot)F(eI{D~~y zoHMEuG_KP|nVOj)2wP+5zCTjAKnHBl{oQW_k#1qRSbY?z zh_aA=XjvDDBUU4v=p$Cm|NAj`(3BIlFAN~veqdUr7sNUJ1h^H5nny~Umlyk1A0StZ zG#9DR+J#1!^pe3qtJn1DpRZ|@zkbF$^E{v~(6vwUN8p=$W%<9M68vc*@}n?B+Rj$k z@QfYMtxAKrkw$}rXC=AlnDV_Y3ej@EY4jUr!)d+Lw^rFZVV9<`3!U`YAb|>ni5bNi z{~--?EQ7bX^)j8ckWA<1^uu9%%sG{m)>~>7eBCtV*bW)EL7y5_*a?#_=|?dB0Bd*E zKOpDti9dC&_;9{A(Qm#7U3IZVrpa@r0GT1xn+D_OVw<)80AVJ<*ZF;35x|j&`@d1@ zsDJyDHJK(;P@S?fJKu*`Ik}+@B?2NtI&ra?hZ9XnSpwkRFo=Iy(;V?y8sk)wU*MAg zkB#vtY@NxiHI~`1d`NP!c-`S;HkV$}md{)BDz@u!($vMw?dWyiS1>nx86go~1(d)A zzWi$*!e0~{%5#Q26MgvT$DixIs>&8=_f9Or*784?Qzh>=gc@Oj54EqM;Y!&%?Hdp{nUl-$g|pQDV2b{`)m{Rjr@i2U-2N@2X7 zSMTeg8nROgE;h|Hk0JRoJ;k4*9tnC}fey*NT@p-t|7Qs(6Aw;Z4qIM)co!dCSNgVn z;C|_!{(+F;mrr*X%04wJ%Z6)1Vtyi_d3zwWmS*8Svo4?5`|^yIH_MYWqO^Gt`>e`9 zD|X1q3*LTY_f4aBS)D|7-7@OtfIi$j>(p-L!}F+F^rK!MmI zCA6!PbPTH^m*Nh5aK`J)L%r9t7wXQ_>Yq>Qh%`qe0HU0P9KJi>&r3rS;_<@d?!#Qf zV&VGIFd%?J216ge06qKY+EK>)*fuQs`Oxx+a*Obvm$*%>pQUE6?%w+O@#}uqLZ^bw zsb3zltz9cj7zTO+IpK$Vkx(@yEZ#<1gO-R+?Xf&oBWYLW3-6bPYPsJWJOp(eq<_*Cz+W5dU+(YO9`8d;SW2kx^j1m)EH+gN-! z5;ube2N@aQnWh1U#-$7R7s*S}KUu#agiT=041+YI5>oN`H~tS&V^n1k1v^4)|FksA zPClMVAoPCMBMca_R>nJU1qxsqzOKCFTY|D!Pi69*Sy#czd>lgmjQ zFj}{mUf}U~3~>v29;lA^SA$}Xd#b!+34iyYHOSXHX$Bohc(h4NxI}2`B}9O0X6$UB z55UjUx@Ro(;+)>#D_j7nWiE~8FcSV`L#Nil6_wuv5NJ6s@%;lOdOMn=3s1-=L>h%0ysT!{GC%f!<0 zj2o>Q9xg5}PZYmTujv0Hdx=jUt#wzSrfnCWP5IN58PYgK zp;gb1oTqWiY)2wLQ6@!XTe!(h;r-^@$1wnKO2%L*%U>mdq&NVKtG6ZV1r0;U4K7)zRH-YcD1F^-)D&U|j z&fOi5#bej=f#C2##K5C4t$vXPT)yhAh3(Ff^>zXoBTmpTuY%M06IMw1B=ySLQJ_C_ zXz;ZvBbrjd2g8+5Z)F&LDK-rq7Ln1Oxva`zp=jj6Zfc)mv@<8TiSFs^OJof_*q@z* z5n(~!KDInwp$q3SAUL|FpsL_;l1w4|DB8TMl%f&3&Iv4i9#`AHN+6#7BlVU zO$U$GU7;gtzt5vKS6UTCRCIV9)bxZ7k4WVa_APo>ZG== z5psyZg-z(T#TC)Kf58``YU%EDtEAV}!pO!g^WdNW zF}*UT%C?}|FJdF5#_p9KG2RpC^~T_XJ2XPJAlefNSo=8P*~O+qui-QHpBTn}x#j#n z3akpxN;N*Z#_uQ%llhx`8wuzjpLdZ%i>>l*y%H0=>(am+Hxf9<0#c+_%S zv7zntE3u1kMb_#+F@l)3|A7%ar<)aVK4H@;{1KWnIoaygq%)wg%jonR_e$&l^^+ci z3SOI}O!)#9X8_fE_|_VbCmH+D(NG#KyZnQ-Ea1ywR856hCE?H%n)oqe$B)y{6ILTu zRZ!gf_CkyC+r_*aV@YaD(1lulC3K%@e5%n^OXZ5hUv~v#MBB&CoJR~&$iU^YyDs4H z+w~k$Y{miJ6WvZPyECZ5x^Gsa0P{Ty!M^;i$HppsP9HBv%-#%!QFfD?q}E*(8R7AEcGGaasXXShpW6rqZue?UL})RP6c%X{v9~=KRNZP3j(U zu3s&=o=>lrS6p(zpu|r@VoFIu`5;Q89`)krFhu%X^TPsgq00vAi0?{U`;r5S@9%G1 zv5_75p(jI;E&Ys_PTAz;F(QO_3yln82Zv&pwA(w?4InE%=15?jo!R zI_?iS(^(apqLp3>J_IKBN%j*BJ`}UZ|^aBab3hG0j5o*Z9k1Z zK=1u_6; z4P+7EP5e4F7}1Ktzsiz7b!c_!P(xnn-i`75$8XLkR~(2}<^1yRo;nlViR|Nbs#SC1 zExU3Tx6hQaMbtXVqYi&JkFp5)i-?F9uvj1NO1hB|E+c7M2K4JRK_UdUIfe-Lia|gR zb$JoIahJiNu8a&5$W!>URuf4+CSThAn@7KWL=h~N*!pDkgrZ{Zn9ZK$lwR9NmY;0? zaYvt^7QU4-V~P^R(HF(H(mtM-ob6{oK&5yoHYX^3j=8;&Md7Rj&2O@~{e7tJuEd)f z9Y2xM^#=JIpgTsh@X<=a2v&#b>R2@!u)rsO=p7#Jdm;uY@A8$;@gM%FG|N1I1_~(3qqDNl!eK~iQg;%%ZkjXN6*M2Pr7t-n@B|r3_5zVC0 z>a5@j9iSLW4KiJ(a;i`y;{-Zx7;zDy{aDK3^z*WX@0^7Bw#_SyE9?bpHM44kgq`n9z-;f^Z$+A{s%F zzTHH=b~{f)Dmd+S{6rtu(E^41X?P5>yEiDGL;~6MThLa;(Qb1$b0~bvu%KuAkPU2ETa~kdC3LZ{t z1$-XLh&OD{HAFwZ_D7ld`Z*=$ADPl?YWyLaDvt_u#vLD@AZ(gJ8-4md^)wY|4HZzv z_Yfc3)$az5>>yA#D*;6+NSJGlCEqO}qii8Di{>G~p$G>aoFQJ0-bP!Nca7BK^vk?O(bQ?8F-FKed`naPyogLQJ$fuI+l z2iDDAyvX2k2kA-ZRSm8_oiRiRlF(;INP@ePKT_G{^!&X3TZm%oiUq5ZWqR0Jq0)u8X9|qQ-{jeEe;*s}{q=0XGo*A@`JrsT3G< z>lutPGZbf}TdZ}ZOrTgebI%^N?LAy`DlK>7Up=~Q_~F!y-sECUzM;T#_y^sdaswqR zLYBd)6meuv2=;5BgcJO`XgjT7_38JepT2=*03^kt1>w7&{;_T;fn^C1P1t1NolV84 zv}^(OlTqEd(IdCv80o1ujCf7PtT+O)M|A5?X>-czQ^_FYEB%2Dk+3YX(?Lv&#}{c`|6OCs-f3uzI`L5f_nF4;UG|&9VB_swQw3EC z$Bl{9_}YUoF<0*M0{MDv*@>FRJ;&Cq1{W)@OB+;vp)|VpV`EFX$myi|XQXEddCys- zT?$hq&8UoLLxNtbA6^=CNX9fh@qT}d=y0j?_8CS&1G=LZ>(6j!Cqs%a=WklObSZu6 zGPNZ~4Uuh^*?c5MY%#2%mumA5!pXvn831!s} zQqSLqKyt8qa$_jZQR>iNvi&?&Jj-EgO)E~WXjD$eNs6U`Q&2T_Vt)g zmNt9wO9$tkTE`3DOLTgleMU}iwBrSpUeP(|Q2i5lU{i8rKYT6-Lil=<096?T zF=@{S*4Mh<&uZ}~t}4A#lZl}bT$6eGK&-udcp_EiL0`-7l)HLa;v$D_vv=FZt8pD4 zX3znWCxuoaR}z2FHy67a^x2glXte;GJ(^j&8@`~xz9;9x*~y0{4WASx{*f+38 z+U*y*U7zPfR^0{h+N?QSi~*8h1lnbzehW6nt%0l{L-$XC4VVHB$?- z7W5`JZ>>N{853yV3GTqzi{#d0F%jy);FeFj1SB)F$(oBTk9H-5|M5KjN!Oee9BZR2 z6GbDiD*d)1=3Nooc8w#sl0o1h$S>;y1FG1Zh}nkEAcP14Rb`Kn5!!<~6rxz=N3y0(?~cV)oa)6bgu z(gU%tRz7&1xRDqx>8Dc{LVS2=*vyfs=&J6}Lq0F*pTenl{MzTm%yTwDvGA1_Y^eG& z7|1PY-LCPv)@k=DEpFjsuD8aOxuF`rMOTd``@-|{fa@Cn_h^AzKarPV#Q(H+1vYXI z*DA2c(9Z)8-E5?)L6wS~il<28qcbQ6_B+m@(`3zR^QK5fQev)+1W9omvzR3waG5*X z641@B^XxP$w7Z>35YD{W{hN0A;o~1B)-S`i#zhw^anrApO1tKI&ul|1Wo>7^cLdw3 z753(H%)1i9d^GB(^4vAkucfMz7ym$kjE5Bc&J>JC#DT|vSxN(+B%#Ds;a9GV9XIo8 zZ$n9(RdJ$3S`KQ)d@G2+Oc3^N+O;@G+_;Q7K|{{IMCgP1U@FzO2P29 z6q~hfeLmQxjKvQ=hO)KmTETHw;O@qVNK#RkI3<%*#X%y6ba`9;(FpLbHoS;+DjIAp z{;W&3+&#SM;@M^S?%R7-b{x{3Taz45(DaGDTp0j09#S7{{2&RB?@r8qY*>FjRih9# zTY;0|WGWQ?EGI6W4cYma^QiJ)KJPO)IG4f7@85%yew0^`lQt7#RiUl10yc0qzO(CC(>}f;wMK zLA!d%S;1{A7BVTT_OQ0VpwHGb#b7hAb-4e7vAw@rP%`q;Mz~W_^U*DTp{wZeej@wW z$}>g&BaO!HuNm1F8Zd{yj-NPTD1IWL*ICse<4{uy-sk-lcpq-{g2T=GM|emRGN%x$ z*x?TKCF)q4?VH@&fvsu|(bvo%9kKaH`XZ7cXjEVTB);KKE+Z8j zU|Y2gqM!J?@_CK-6}*p6L$m4GL_$K7fY*uN{2tF9<@jIPm;56c#u|I`<3+2FW@5d3 zuT7g;uUBFZ1A>DIs(E_(6~jDhXKf8o*T9uqvV~^j zoD7lm3ih2U|LSN(f5>}sT>pxyxEWvJId1bB38?eoUI>Sl#1BbnBm*l{Bvj?jLb_nu zlmCaYw~oqcd)tKt9|-{|1qB2orAwLz>25)!q#J1jL8PSxrBgyAq)TZKMCp_gDJcac zq!IY;<@=h5B+CrnPa6EGRY>MNx5t6Rzkoh%;S|WxI>n7Q@XpwgP0wnqQ`hpENQheW zCCSSR9hvso(R{f@($RJNH2Y{z5XGUOC=m(f`7xMtmOR$w>^rDf9WSQ+9^HrfBp(kpB~l@xIIMl9NcD^Jw}5 z4=9BxlGA7u)}pF^Yu^-h4Fpjt27!W^EVYfnquH}NCa(S1c1Q#5aNaVO2_1`GO zJ!%Y0XMW6r>4%?Q{ zK^YUV$nXp}AT|8dHMVLJglHQ_2G&ueBMzyN`$ccCm&_X=q^f3WYMQug>G@-CG>Ag< z-=2E(+o*n7LKkb&o5;YP8vWOv8YAFWJVqoM%3=dV!_SEER|#uh3tbtFKw7iZ8E8?2 z&_cN{-1!1N@o>=7%#UJ`U(+%iwSEBun-tWMf`T^NJeovx5R6tuE3`aslew=?ysY=!ETuA+r^fVNlcZKR z4Hty4!zVY$UhWim20_V0k_A^U*WUnsy@3*ts`oep9&s>;H40;oHTcLB zefU{BU&CP5PM;XEuQ*wRMRJ#rIMM=vOtZiAzezi10t^LL=PmRH$NNa2ONha9RITUD zJ^AR)rkq4)@G0PuRB3#7iDl*FhJ$fQS7H9Aa}`CX95MGFPfSIh+?;hEQLA5)eJ}^( zYr%CNH38M@uv7Q`hn-46VpBBgQ^$zauYm7okddzTaJ9Sv)SDLM=c)|z>u)WUCyX1t zULt~Az~?0iz$GNiM{50G;aAorQWl#gTSyhA(yn?D_NA6!^H==~*rtVV@SCO|*eFJW z&X}FH^A)gWWN>zSNN^`GFt0Gtp0p1GYnFwPQMT9R_Z;_)U-gs7s}K-)zKBjK427#Y z1e3}-oFo7ja~qVefVkpTeM8VjU7|J^?c)VJ(TWFqlU3Fs?LZ*DV>3u=H(8mte?cQx z7t;!?3w{ratsfx77s%02P;kE1W}JcZB@3H>{NLO43hVKkMjhD5M*FYBg-mmS*J~Aq z1Lmn#JkNrope(T*ng>0*5r2$}w}pjMAhwo)K5$ZEZU%l__PvldO=1ze_x@MZ7|<48 zi|{f*#47>x?w4W$7K}f%QUu56*+QV(vjHR`V-|$pnp8d z!uNrax_W-nL+@}1u4q4OyJJIWn+NC}<*p$$xvt?tNMNq$q?CjrRCuVVO8-r3H2^A# z%y2WPc)4D14ZBv!w0`5RdL$pjOGpWVBpR~o5vb0Tfk80Fv^rO_*jMAQ9XLLO|Muw- zv^#Qv$OXxD4KI0n^K+ENe}_y%2kGmngX2DZiuU4;ozuH~)ks5kVq zf7)M7xnocNbR5bFai`j_h*kNQ7wIPAdq1eLOSpb5EisYFA6PJk3>)A&?8RwAAJDpe z%#?1WF969+RcI?|&<)o4&wyO*GZY!=ijU7r;<0a2d>-~+x= zJJr&;GL+hq)q;XWGU1`nrrOD?*xA_;iUk6%^AMuuw2b-c&EugxEWS*#hNV~69ZB2(>Q~w~q`XVZ7aeEk0$_JmFOEEBre@OPR zhk*y&Rjg7{Sv5y1>Cn?2U)L__Q-Bx>2zDr+Cr=5KB_$qU-d|5ta4d;w&k;wTw!^$!LQw5mb+Wj+V3Y>l1vWI&*{8M-0g zY1*H}qGY1Mtk6QpG$h`q#FO2$cUv>s|5|63-G&@8vxf>rJJB<5{QwtJinLtGI{Y-s z7itnnA1-7CF0c&{>XEm-Mf)pDNwwO#s$}vEOK6v#R$mM$o+5WUB_(Bg74Tcl)t_K; zS^*6zUgbXVddj^~6(-*k2zPc6fUVH~&d3 zhbyeY@^1LJ8_35kzl(vhzkk5Pj>4G7 zeNb2xpOEm$TJbk1oX&&zurcB($8O&bL;2C|WOW-=TT7uyjgYt=`onHp&vQ{am~@@( z&AulQCGydE9NI?twmAtXpQQQC#y?k(vQVkA-B8Y@b6GhkEymwTw~?0UI0$aAWRyJt zN59oV^ErlQW%7Zs4e0!g!ZbfP57e|6L;rmqs+FtERBWu#N?PP%2rRq_9A5TvhfGNKV{T5b5pozQz z5djiX2NxT8iBWj@5O{e|6m%Y%@vUn@!~>zEKMh9%6flVh?W`oBM3AGJs$(uixuzLG zf$=U{@~eXcax{E#CCcBIIho$TdGOr-ny9iv^a6|-90Wl3wSHhm&nqu;4_%RWMip}x zfcd+N2xx$8)m3u@mW71>uF<5AaKfkv9r)~OTS88T$s7_LV71je)Ooj2#X{{fUk}Tg zk0borR-A>rv>+@zDyuO(*uEi#@p6{*_gKQ!4RdqzqcV?)*{kDi&uaFd@Y%q*ed7Yg zyN;k#TO#n(sMl6Y$v89K@mX@M5#}2FqOr*LR!6?~Pu&NX0QqS0_22gf-a0ZmBE%D* zXaDl#=u6iaFftxkYIv*;-fG5RA$?@@8ARfhW5jmC)<|Ac5D}rNlP`RJX6gby=#zf$ zD;*7+$7YsonUW7cQhzoIk!Sepg#E4jdgx=6j2~P=kw04cp|Gr3iH7dnzv)in zLLecPuprsTix`YR#UP+^jbup%{pF*mLz9$CiM`3s|D#t4 zjhMN|9UUEmKsQkbLc_idx#OXH>#sm`)nl+RqaR$%fjN=t*Gcc0f-2t1bQa8cV>1iP zg|l~&fC^=uoJeX}S2m#n*)Dyt0zI6ehtW!NwvWTYTT4F2*`bQXuym@hZ6WF1r@PQL z^YAPfCgCVzK3-+#fU5re;s@DVKsV)wnFBy>1 z$qs>B7?)Z#dRFPsSzu>z$FflaJr3}>>f-J9XBa(v;_9g(*> z*p>h%_2Xx-k*;C|DR{7P5q`FhBXQ4*$=Ka&BkIUCe2sNT?iHry{j9h@rAWabxM^1|lC(6JCz|6R8b0j)KaC494(`%{KQ2 z{Gw!=^G(0=G(?Ex(=a&4L2x^Tz*1A9P-}$aC+78@#Ipx3PBXid>+JgxAIu!ztqO;H zFO6IbWWNsXG<**BTyxR=9~P7kyS1SUGuL2PSh(2+$gm>4LGaV?kbCfutDa57{wABz zSAI`!pfQHTKP1;0h!qU^+dz8gmWt0aKj}TK`TxB|-yR{(2;gF`25M>U*bt%jC(NnY z{Qg*fhCwv`>h^?M3B|HBhpkSBo6 z(E^rc0hDJu7N|p=Q0vzToAq88{zh4lum9QExy{TR3Uu<-7nfH2h|AZIFJ^Mfar{4D zOzG#H6tkS_J%#^iH6F;bkSqR^UB-v7Usti#UaTNFf`JQVLAIVkD+q!&AX0pN_F^vd z79T2fJ?ZI3mUZ^II^(~W^=ZT+GJIj|htmJBIV+Oa;1OyEuN+pqZreTv3OWot$+O@s z%|M=o&=#TdQuc&uw8S7Oav#tVVR(X=kNwmosy*Fm3G*MvVDqDp%XBrb>pH3I*bkNe z;duxDp7-J)*5Sa*Ipq}K-$SCCjqTQ2#xNne)Z*!xtb|qDGXRGpdg&^$=JJpf+CY8^ zf*|zIqR;7H&BGCyIZ#NtMLlXG0r$$4Uv(^bO9kc0jU|f@J&!OIxWQj$B)>^WkiZQ# z^4J9e@J}G1yhWl35K3j3(G|S+9C;0o*>`!}M1(4_s!B?9q3x1@am)oyng-DSMx7PX zn5s+$(wm?Bv7#ogtE&^kn$X{OTkg#Up?D=q(%;W}wlYojkLji$KuP80w!LfQ-+ql;LwPp{Ix32!8E>N_o)f$!lm}e)nE0X_kCNo3tK?cH0I$ zPc;MwQC!UadmFm6i25}E^OT4%W>n+n(ere35CtDV`&$+UqAa&`$L`_XOj&5VM*jOX z(Z+XMLv#|FNr_bQa%WZ;QcisdF%FkmMb z)Gk17DPq_7_m`ba=hJ%!3{x@Jc>=Ff14W-_p>Cdl&x z*yJvlYjj{hi1!6NTIBl8Y629)E&qO!ZAC|IyU)_4O*iG4TK9f`2kkuE-%{mVt~((5@0Fg8_DN)}6e4my)zz zzxooII<&lC%jtZuA6>*y#L24CUPNGOBhVm>4<_T#-{Oy8( zhGKQ=rT2&!tj51;KFFjb*xyj6oghE(h7q*JN_~4vR~kei+XXJP({|J=!>;{I=QbxaYH7j&B!ZE$D{XfT~r; ze%H(SSYhhXzj#B`$_oXbLe_1s2X#|pl+&O(m@c$EbU4rQpryTp;hw0}aP+RM8JQKl zo##679VGb>Kr(0@Hn>|+zWpLLxX&=fx19&*{Eo!t*o|0z>dLCBqp3xh&Z2GDZ>3(P zH_A&*wEndz^X1Dn!5qu9q=pyRG*4qcLe6NeOrGva$z6Q`nd!L=x7D-@BlPlm}RL zR(AHq8=#M^h=hSq(%Hjyh-W>?DtcoxkSK?cS|Lmi7S+GQ5TzWbcLX0{EBioHe$j44!cA8_4(DSbKsqp7MnbMsCp~q;_ zX7S5Qcfb;|j6W8W6f5x2u^OW0$)+ad%{RkmtvWCj#R*df!*?hyg@^Dn2K9E<7of7X z-M0WG1+TYIQrKE@0l3z$qg#~IZCMdt7^nDVs|YTRjEvM-Pf~P1K|c?Oij-bcf}|EP zp@08A1wp4A$j@%K)<53pPU?Lr8)f-ix?Fd<%=_bl1w!%r7JdQ{tw zzZiHM{o=)A#>r#SZHW$4;w3z?L4aW79wOtNmnjvyX*+pyZ%we39(a9x_Ob@l(~cqJ z>G?D5KB5|*oU8!i4b-nIdI%bsBg6`srmB2-CZ1vY?5}I`ih~OGE~tpHjXxHV6!SWG z86MO_Q>F~t_=&$L?YO8%LV}$w>R*%ueWzGB{wJM1I`H8 z;!2uYlPmZ|5$VgRw&#G9XQQKP=xHuDtty=)7kYe`h)@^3?kuzlq28kL+=r+AGZ^dS z*Lj~lx!5+dv{!i->aa@dn^@n<8=+lodDkR}%1iyKXHKfkYp5j%W}X5{D!vyP%mXPN zoDE?~vG@(eNg1CGnMs~o23MjaE&m9?SO$BDu$(yjvTJBfl))<=Esw$YkwFN>67n>G z6m+<*Un>*w9eGcmQO2orST}-mWD!i`x9_}E2l#6?TjbnbJ@{2=*@LL(ErvtYEguk^ zsu2W*wy`Wv2bYn6}cpd)T3}0J?`XVv}xKz2vkB<7OXEr;s$p^`?jLe-`m0lDuZG#`F zE4-Z@v?D6N28Qadn>Co`=$oR6$u@T(4zrtWZt}bIfL0Jo=a-sm_&$^_v;6-4py?QU zXC)6|Or6bu_=XoP^=Om#_JVBXNg3NTN2tlB+Qk({+&Q%7D}|vNxaR^aaPtM=#How@ z_)lW5FeFWOS6b|FMFQ$e9l?G)x1=3mH@A2lP$10bR@2`$B*Z5AaswtWwuy5)R*Hoj1beE# z3*T3HlOgCt{i(APQ7~9)x)AwYR_t(-y8$tZ=jI=OtDE54c@nmZ6O{`fH+G*!pAfT_ z7H%xZbU`8Ub?qmgf0ArWHe)%E4mUQ6on1(K)F+T)VgK#hPk3HeTEI8VHgV_2ykg-8 zGLsMQ!yZ_T71LO~zqn15EWg1%MbCs8i7R>+&O$~L-Zw-s8LrlBX!!*cJIs4w>}k+& zyU1O@N?E8}ZGA#ft|~t%7r1V6Lczeus0oFF9?lLrVIo2@m-zm^V3RUFlSuNIgJ7pC zu-U#o!}@hZgaIc#rLebjTgl~Xao2;UzE+jvq1GkAWTOA#ut~HIgUPI{K5@5&l0mbn zNBF*jaS-rLwdCZm{J2?JBY@Xe2vTFs*BHDwJA&q}@D@BFS|`AKG-S7xx%J%za(Xz` zKO{NwZ_2`MrRFcGwO`kEJa6|VBFcbNbO;^1AK;IIhrDX-dX^d{nXuVvm~#qGuz_k1 z%)05Pc@Y+t1!*jBF5@;sa8pUQX$#Ep9m!BWK>-HEB8|*{-IBk<-wyKI&Px2|2y2n* z>v7FD#bbUQ-h_fQcD316B9{X=Pd53c4T$mHQ^jO19igPU+>C>;UWQQIUece zLq%-6j2pv^o*LyIfvXw_Wj}X3o$!O;^Zv>zn;5UHyVRqZ<;We?_)|WOc*Ffnll*%GE8P2ur>JH3^qrL%E^nmv9eJ3z8D~$%70y z`%Dt=H4?nkQOoQN5&L1GtqYPHEDi9@aQQd8|8GGGLqOc=9pWI?y8)*O-x;Tp*mPe2 zXiH^%Ht{BmpTF67y^(-uJ;-`h8COqF4-k;7-cVO$VQ246k`Mk8bRaY5Se^?@!4ZR{ zR0sWAO7Z`Xr5HR;vY{a*m4+_R`w;kjXSec>e4_O|&u5N~oT}+UFaL2PX1v*q@3Zmp zYMn>$7hr6L&(Th)R?CZ_$O-M#4UDSgRSKTy{Js+&X%bNC6wKRcbXaiN) ze?^CI@4y3@t;`D894{Pk>QSZg%71Gs_`j~LQ&d<~)W8MjwehX2|MA)9=J6@`6ClbPQ##slcW83qh=h!a}wZfYbug%qc(9LHJXtR zQEz9diWMZ7=^!!4vTEH3H&(*8^KxpG3^PP^?u6OCw6qvtETcSjK#pYq6G zf19RqQWCcGaL$INireK8pnnji0Gs+WG7Q#nT4-MIdWcEchu&DyTCskZBCB>KG-zBG zgpFXxJ9ULRF<~Qf^`4Sm&M9OX0G!b@EVpiHwfSCOQ%itTd8Y#;_Ip`CN8^;sbV&Qp{e9Z2guJTyic;)N za}C^dd{W8QkI1V|Jh2hMnFv8%)f<^Ahs?=^X64E?c^MfEDJe|AvUE*6_bMa^V&!ti zY_zn5<3p4+(j?Z260EITO)`E~xM-F(SV%rR(KbU>R&H!nVHxl0=Jw1g!nKC|ON!MZQOU21L4k6)+3xb498R|9jSlE=~p{h520Ov|&l^QGY9i+BB zb@&8W7==)xOX~j4O@``VfU_z5Oi@*J>EZ??_d8hJcgy>jH-VqxMzMIG4NJ$7`;K@` z4qX31AsnTv?_pTEe)H41SKfX6<6D**th%MeZ^E77?ig~de{V?gtMK_b%s4|NkekYp z>%La+G%x>gcQ{wwY8pLX@0HGPgyjjedUQ&}$AAq!M zSnUK8<9VXDweS|&@Tj7lP9coHW8F_>7KkVMzz__BaTu2q?S%dMI&Fmc0{gedzd+?s zVu2RWTSuXYgW!eB-_^y!_W@_NXng$p+k17}_W$lOxjq`jU1+;K{A(}lHe9SxUq(09 z&MaOZn%W@$L$CsooAlL0CNPJV?vrjDS?S8v7%Jerb0q@5s;e290lV+GLj(Q4a! zH|;qZY;g81`FMHdAuK~U65yLw0kpa(#c|@}I2LdaT(O7_-~a70Z#M+36UFtr^n@Kj zFRQ<3n-ykcG_QU4Z=jD?bCJ$H&ue1AtxWDf*KHB_6=ZBF>w-Zuq;{5`->ynj(Ps6|xH0WP+~ z^^vLRE#uGU$}iXdTMNJ&=z&V@$QV1wmh&O2XH*>^#V^`@^X_47gUx`<2V7DnBGS#t zw!h-g#6SKvd-nFMyuUCEI|IY#c4l9?)rmnlm(#EDGIi*9vI5!stF+^3+^vbVfr)PZ zIkf4E19;_iU7zCFEpU6R1mK*Ei_8f*_I`(qu70CZEG z>7fBffTaekpH z*QY3p?aQ>}+XQUO<5P;cY>SQ{Y;G(Dq(J8v@HzNBAi^j#a#vVsCw#1eL}k3xlgTfE z4X!OFI|&(sW>-QdG6Mjrpm~OC9)Vtikq#zH5wu9o@h2nW^~dX@{WBqtXifglCKtTn z2TnuK-bBVvJ{{?T65jPO4g4Z}X`>=K&!NolT?g|nsF`d(b>Ip@CZ|EGSP7kPjkzGH zUO&b{8QA3U)KX4)JCi%eTQdV*hG~?EnRx`FA+Kc!2Pk#~QQI1el$!m$hylxy2^89B zy{=7VoW%%r;ygH-Tzx1O_z{a#!n(_3?%Dm%So3h(xBe8)RhnyDqiQjE{g`|MDKgmj z0YED6LG7Eii-clXhHJjCz_fDy?obmag1aeSl^U6Q>5R3@n1^O+MyXF0T0rqrmT=YU zxz`}EBav(x3w(w^=X6z?PuEA^z6jByH6evG{Lz9!G6v>-q#~2hl&}7cr(ihr-QB$U z$bG<_FWOISfcHHxITzvdJCReKIV(rz$D7 z+9Q}e+(!aSZS(5O95BPTQ*ZgmN>q*qw)*il10W;ukcEEiA1VBKUHd0$Y{2Zh>HVVEP;m zAJNA>DSk|IjqK@wPUs25(?SyqMPvv{Ro4*{^&=(nAw8DPg4Y+LY5;7BRP@Qe2ieIx z<=_oF62F+9zt|HYA_T$1`*l!~SmMexh&%`$>S!9bt_82V^_zzHHw6cLIGL^b2ajOi z*!{BjVY5CV`__L^7k*@df?*eGHBdKPGU34$SMm+}uSK%ZIm&^W97}W~1l_hBVZ_}v zV^9nM!M`do$ftKHeT~9yfoBJm?XbmAZCh2EfTT@jy4=R+$bOAx}L4h z1+=M<>uc6K%1C^>NPUa<1|uvd*!jIiG%V+~XBH1Uh7l|c7X~T`e(Xec$7?xf91_=L zYFG|n9ex6SCJUhGS|Ix4{)l@)QnxXYg(|Sg(s0R5+Re?4g_n1DDPdlSUSfe=R^jegl`0G1Dgx=h-!vZl76)2LN1abm;N5j zb8bQsaZbl7_w4II`cu9(Vu+zf`Fv}*jui+#Yfz75R$lHsQ4nix_=)c8A>{nrJ)htg zMERU}3DDCAE&TXl3;crVf`E(I!vHP{@lET9P1EdRy%KNyzWr;-*PCjc=d-SIp`VU@Qf# z<-xuH6Pi0xrk70uPmx&=fRwZy0m7)KHyEFbXJ4<(kX}~GR*!=FLnsv*Fy8qS*{w#i zq#dTtEUo&RazUW<0bU{M-Jk{$Y?*uF`r0>;xgR1BoSu6h0EuRFZ#?$DUw`{Sa8-$% zLth4DrWj!=VX~8!AwV~>x`Rz@Ze-s(^gR~#uB+1ocqkaPxv z-qL_|u+2a-evzB1he({yE8feT!wDZ9F5}_m7Yy!b^EWbmjVP8MGQHLt8bDS+GALC& z!1BfQ_#Blna93J5M9=;2B9EPR8Lke_yN=U=1=>3d+BMG@x+NhD7XFLRCfQnqWE5ZB zYy@#8!oVvFxV}we0r2>8+AGj1NdkS3U*pA!I9!gjm+taQ!QsWBMzQvpi&OHLp(^zD z*9&yZsQc0cW9-IDOJ03@4~2(jmrAWt2qci304)zi+kKcfDu?vU;Ce9jC6P8VKh0)P zqXs!T5a-GOm;ZChzHHB~HSaH8_1-YnRK^k8MqOi&tF&w5avA9j`SJLcfGM4I6%Mv) zkBIkYewvFlnA7+X{w+Da*}1X%RvT{~CHdtvrHHO-|JE$qtKxD>l{JQ|5^(ny@3}FDwL9C->ET`)nC@#-R9^i{f&$y4 zwe+ebR{g*@hiJow#~h5z%=aKx5NrbEiXjAH*RWkB$_ay04+qK*VHPV!iC&eQt;7FW zYDn-1Y@xIyCfRJ}%0d5G`{44!>j$JuCCBfYq$mA`1#M|YUi6&PV;lL-9@;<3D=%`F zufZ-<{yKA*w!kHJ^Un$0lr_1<@bld=n~kFZ7W7??tg&DX93vVxzP;kJf-2)7ku2V= z*gYI5E}~y&e?kTns$*G>-;CY6DBuh%mB})S@ z1=M%LBhLDKZ@(g9J?4VSt@6jH35q3$64zQQVbSCZJzk}S`7ZiEpl-<{e`rdq5Bx`>e#p~C;p@M>CujoeitbY7bD0(P0jgEf>*M{IfEUFXGYYha1{Ld6`!^(~ERN{eSna9Ssz0aK2KkW+m4ir*@AC z`IXLSuTZQA{xl#~Itce~urYpb%#hH69?xG1?CN;dB*^`k>X@WW;_9JZl;owyS5g7Z zBSExIi~?u*7IBvDxuhC+KP&9cLTN-)Y`pQn#1;4ZnO;fFvtCL zm8^Hf5(u-C8xZ-FsQ+@${oTb&Cu$~;^C86)AT<9PzOK63{jn*XRn~4uMK6*n8O=h|7uCW(NrJWbqd}du@r`b$E5UKp8Kx6h` zbgPeIkv9#(c`Kg_dqEd)ypV97^5*nK3`$}XzOgGb;_FGW&`d){sYFCZg2pBVF(vn! zOIFnzY@O}yztAMMfxD~J-pJu`VP3Y)ViIoEY5gDL!3N_dwSF2C4cXc1DSzSey)fgb zG}*pxV;bihUK*m9@-L|7DHZAy-<$YZPxPJuHKM6k34m?kU+&+4Jh5Y(&2z)AwRz4` znWcj3>DMc8j&seL?x-Wy*q`h#PxvzhC>LmzMO0r|A*-sPCdgKL|I6MQCuDf=m~XW+ zB4f7%C(nm5_Ekl~jF3S14j$g^J#||YwXvB%NJy~HBYH>uNLc>Z4!J%a zW+imfxY9nGmQ|ygkCrJpC#sfkYMo})^3|?ATAcvgIy8rGgoK1#`{4$}1Q_f(KTwgU ziYQYMty#A_@8{#FUghNg@T{x+|Vbd$BxkuOx^1 zpuxMdAeuAD!c7wLb$f9Y?YgRFzQu`3q4r+`9hF#tG9(5wW(Z~*R0n2q5OnhNCjgjl z)PxYNH!V~wL2uu47}&?RMMcxTeNNOeOS}FaTzq`fVT0!7a7$9d9A7~FR2Z*T^c78d z@2znbzYWCCiE|=a%Dl~6=53tA>Uq^@&4rAZMDYh@lblPxvEw{e`M+<$-nx1xF{5XQyqMx*^T%{2rv&p_qQ{Eems87In)eLt!j>Q`Qy1! zI+3%=pi(LhlArGmTp~C;f7;tyC|r%UJ>=z&*mugk=WD>|^b;UQl!`F2StWoQh!Vd> zKHtEnzJjw)-8v!m1S%QGkTXk`JP<}mMHI}n?*G`7V_`^CGugzcHT8fb(B>rX_0J8` zk!wDeE5p>9^!{!t)Xd1}H2JOMi_xqqmV7zBQ@3sKfPzuOA45DzH(A;3N{a+@DHZGe zz(4Zj@yCQY>rFB)_ikQ&SW#fC$)5Y1Jjk3`BuT#hUOS0qdy3@Xe}j#l3n}01bOf^zw*rlc=&dKV}L(Bcf&~t~^{bDhcCHZT?e; znYn_)^}JsCpxf2eb@jo#xcAbR>noU8A=<0y>^`nMLkaD&I=UN@+8fO|_UL}rP~F_Z z=p?OATddw!V|Y&)TCD~u`8NougtEkrdie$hb7RDd3>#iclzZmi8n3fw$rJtkAqeRe z>-^aElm=}w(yH`(zw)WQA|Tu(tI8V`9y(q$P#Zckd8uHqq+a7)-y8AR0XM;nHXy<{L@?_2fxfoa)`p{!uf#m8Pi1OZ9J_! zLmDWr8C!X)YAgWX*!9WhHTC{0#m)X#NkuL_GMI?&Idt^Q%s3G&!y&mOMA~#XTudTz zp+$UnoFlzK16tl^!g;$N+4^t1Ql^TpDpN2l9Q`E8fBw6XQ%P&b-eb7_qw1ZUHmZ^c zX<;KN@0ZJa&wZYs$aP#5yaf-Cig2;-P$j8~UVBbtZelm0+(3bE%$KD9z{9TN)~r zqZeZDwcXU6-nkN@H9e#1q9ry`i3Z*9>wyD+_|uAMQqD|zT!#&B`-Qk+?hxTSY8a0V1aj{d1Q?L2Ec@Y*rHb;8GDj$=7FY>Co zSMAqZI2lTY%Ps3!BkWT&wpv&apAXH?Bv$f3Uls<1 z|EfVfS5@O$&Kv4DJuUR#LF;QLuQ-=lQcLOSG8gVVz2;O`f1~7~@mXaH&H5(Jl~deC zKUZ;(-itoFcBFanTd>#t5kD=0+_!rtLjo3iG5(q68nwMN-<(2Dr7})MzK?8!`5Od) z%F&}*W2&?ce-O&PfVvLHC+s3oY`g?*;3+iM4v&2}Er27jNV)W(^y2AgRn=9Sw5@a( z)C9StgC4#>PjJbPL+IF&7#u)C?IJ!{#Z;?Fm1Z=M_)$~zkfM5%)Y6fwo^s?x!B||s zn$os!c_c6D$$dz_&J}%RY%F3K=Uqy07MGWY0j*)v>W`saVJ7?4?AF9PGsy*GNU^?g zT@}9z9Fn+wmz3w*E%ZG%-QsZXa{B8HaNkZw>9WL3v+nY~oMxRWvOvzu(vwgBJlQHCO zptB(WHTOrim64{q2d6@l(gi=k^=r5xFxG^5-7kuBIseEaIk#2P`b;%```x{2LJy6M z6{!L#``6S2w?~lRy^P`_rZ*Ykk=$HEwYu$63S+aSfRJuTxze5URQ22J4AXO|ni+|x zU5cQ}J_{f)6x>P3sKUjy`waD|pP;#N&#_{1-yucgpLc`Aj^_dp=EsHKSEYLR!8ld*3FJxV_ZweupWa;MJQJ6HV#RoY4o@_hI_huP#$4Vcq?k9-_0 zabyKOHB{1aCilJX@YWjAr;aTep(Er{{D>7qb}?^uP13W+%)2PM8>z^fehYn`pej+u zV%Skf`t|Bz2IHp(>7YFxOx{zcQqyKXP?i&OZ&tf$g@tEB z89UF`!bK6;5gVfKxyO(W$Ze(92 z)x0YDT;NJViW=-GWXW#{4hJTecKudL)kub_O$hMP{QB~>SsII;Gv?eT4_FVxr>HrQ zTygd8clvV)U9Y<)PxzH{>YMVQRgT_6oK;~g%NFW~kQW2OIKr|1CsRzx1n3SSqtj-s zDc_YD)(x9KoCfnB8wqEr?k|D8qy#7*nViE39|k3eaKMOI`NAaS8v7MP3;kT_f&N!= zsxmxSr2boG+|C(AK1W|{rjlxUHit(t*jC^8YVJOG<2E@kK~8n`zNP_BB8PQrB7dtX z0j6DGQ+wf3yl1IGtdYcMGuBXqBhg05yy}KQcnjqeAAeQHCHc<5%;F3yf$ZM;(9txx z4OS0MJ{n#SW{Zj9*gfW{5S(?O^5syq*{whCoX0iA3FF4{{nICC3z=@ZA_#@qLYMpF zmZUToqh3Y`-3`wQZlYA^=SbG|E`o5Ee$h=J##Q^BKQl8s1>HaegqQ{3OD#lD4W#t* zcCh1UrL0+!_kZYZ;7WK6Wfl%GE?-+7{?g=od-f%{##eGdq4ApY(YohNfBe?N3O258 z7&BZhBhhdvA~YiPMSl|X*4d*b`9!awRc>vD7L}TA{v2TAmk=Ix9@9d(zjOS-w||LY zX8`Y!_UqK3)ftM@5XW2{$^+jirQ_Y+Z&HGHMXE759OeZYBv!|ATkBbDmC{qbD37lT@=4m!8eUZvj5-!Wa_%+n|uQh?K=fwL&= z`m>Mde5_2DT43ubdH*4ED8aWzVKPQxTN>%Voj`|DVKQxT1wM6D`{=0a~|hZ2Twte zf#R|m!4jy->?#w`7wfT7OA3n|r_=W1F z3PMn7F@?aCI4qlBR!!|V2*2mVf~?2_*)h4Yb}J%hk}dgiPYm;%QxMVq!nIkqLQTOZ zmo}+x^*GV6cK#kaCeg!=9eLUkJ-6S|`W}zzLcU|S8YARyPO z+8MuObmcO4Vk=FwOfgYVUV)=sxxA$a=mc4UA|6$GF0O76d*Z&l#$cO6yJ| zfZ$Yte%lHFo!^rbLTXb9C_S!sE2i&v5s#<00&4h~S=H5d`knrR<-OE5T->iUNFa|< zPrSv{xO$)E@>qQ9FTS4Dwd!}qTekY;ogvX-Y0@R;j>8|cujUJ4?7y&?$zhD1UIcQC zphIN*=FiPeaJC?K`jBqlz72tf0BA#&{nh&v@;}2i(`WL**#0;6kLzqw+@7D3^_Gtl zaw{#PdMSeH1yU`|d;y*zD<|S77x6DlQ38H~F(wYDB=GkGaQ3760KIMlL~yEmb*@V` z;ND?oMqAm%)4Nq7$^o_H13%SUNAH^bQKp6uHE zbx;allhv!((6;}$BUJRjAz_so=pYr0*wAXs|0@CmRpX5tjwOFTapAlYaM(mRv=r#> zLh)w!)rq~BY?GaMwkx(`8_A)-2I=v7@32Ya(B6@2_Ry|=B$r3Y#gH}S)>WQW$dZqQ zj$ud*l4|N3|IiQt{=*XFaPJ%OOhJcCu9aWI@@7J%K!!(IK%bU*)mOvM6BXu#z@9Jd z@fVN&&3-qxfb$3*19z zi(PTu8~>r{#@nZd$<8gc=h_(WZ<_HJ$=E~TE<{B8mpX@k0+!}Pa16kW63P- zjO5x2mhTj9o0UY$KEWd4cE#`R90VN7E|L%;jZC{G(2OVq{BFmyPcQzRPTC22EC~rM z%z(@Lv(HXApv>B^Ko*P zT96s0NzgL>5Y%^f2*l+-(Op{OXwLaEc>A1M%5enu!wfO_$Xpo3gm8jOYgriL)n;H6 zblUgADY>wH*yES05xDA|=`d{t(Od+AkX9w4`geS=S!Vb{h6?jt`bkzXj~7jRlum9l{KNRl{*Ko40-@)dsAUDr<$Fyjzl}kbPvL5;*+;;fh zkhPonv=C5>CI1G47sG^qo!kGPPkZrVKN(vPeA?nIu#nWo?OH^)r9iGOdYBxB29g8YZu1Y=adEfhm@hZlFCyI1!a@|&db~*Hqla^ineEdvK zl3m&@@|I?$7)*CYL`m7kg@}V%&wHko@M2yF7W1UAToGxy z({ZGHGpAlUJ;&E=Q)fJ)SUp@d$!8$AL6TTOOepw;u`rSL4R3L=;xm={ikxGv`rTr3 zOMCg&*E}{^HI-bEllprqQBXu`_-uyAEJBfDDK1vb>LUSM^Z$*TioiiKO$^Sou2qo< z6@I6igu2a@;=UW~OOOXu+l~~#1dOM-nU&q2d_f3K*2_ijJxrx(rnUeain^IGLj_kN zqTtpYs2+!-GI`FB(Z{AA`0jqJnz!$MX*;rDl4BxFhRxFgao^A|_2< zx|weWBupLlL^bvsq?u7&{r$_n;Q$t9(JMcC9VnF?hbfN{{q2C;@~YuzlWKp_stujy zvngYp5Yd8uzFXRDJ!Gl}_czsj?FfdO9`WjK?bQ+5>`fj7%Mjhv4_G$-!y+3jcX?9$ zPPZUt^9xB|wi5SJAbgqieBNIhj{$auzDSTkHv(0H7D+zvQ{HQ*L#O)-LWJv`3Edbb zF|j|ZFB3h7mSPeeeUqmU;QI-i)wm6w`QJn|D?wI7k@R^pxYxi_z*xwEa$bN<8Llr6 z-nNdHOHHP43R3p!23mt6? zk*c_-xu25#!5i0&XP7|hdcHUC)$C)O&bqGNdZbb9LBQJTbR8c8<^djpq2l44lvd`# z$e*EqUQ-T7O!Hk4+4II(YS^#y=&vqA4@&Yp8ugPEsp`60@K~6=EkEC_e&mEgkYu0#>?B>4kxV+Kf zPa4v9fRcGZd3o%_D|!cA9|1}Z7;eSkIhTLto=7`|-9M?MeoWu^VO_*|?t<}aA@u1l zo3wDw|4_Ab$(~ZEnD~v++&TZE5M;ksQtx_8bJz9HK>FIaxjENtSa?Fuh-hG+RT@zK z5G^*_t)nsDpAPaX6y&VfGCtRCld0}pCC%(LjU#^uGMY0jE=#tv&1jI(44O!47V2e= zUB2p&FLddfR1oT$*b4s1JtrbzUH1m>V4;FBQkiQ`tejJ`*WK_4BGYWeX>s+ppntQw zmgga*_sdWy{H@@Vm|t^vl-Ykt6wLqL2s$=6OBZ%qg?Mahji=UKt?c2io}(ijB3|eO zOawx9WblDl&R=2@H6i#nP0)!`)I6L@W!It#6J#i40F0CiLl}VBN3TzP_82~ny`ph% z<=<-$4ewKlK91swbb+ZinH|mAW_*qf9&5{R125v1qnWL!o<3JwqUI^TpHM{AU%lXs z_x<6L_%CDKUM^B?b_p$9%$XTtsJqSQtO2Jn?_MGeVjcJ`P8zvk5W2;ZLDt21*dPKoJy%I?yZZ3%%GF#Gv`A7ihy3 zxUy?6P5UwO9Y5%OKW$Q|y~QE=;Au3KFbUs%Lx23U>G(4aj=TH=bNZ1*%EoJ1>8H1} z?PG(a=u0nit2n1jx(h?YT{oWCI+0FeOf>Mc<0-(DKP8IQjecOuX!fNNmWn)2jkQ_x7jWau^(flygzHFF?jIsN^q15@gQ6aosKytV`@}g%d8jd_Sc2nuHcq$oXGL9;x1N zWfeUgUo#)%jad_4Cf#I_!*L#Xf2U@tkq;{H3tvE7Mi!!j*H$))(|um^NnhkGQ&pd> zV-$XfkGw4v9Ek}d2yH3bt({*z$y$GLvUWP%WJ)4{Ks!CK zVrAL*fFYqkDDQ#-@Cs#lZ#WuB!?Pdq%qA0BlANA>&bQWfHiMy!hw1kI%5AqW^7bpvq~F6ldeS*zJnu$v zB8<%3W%$U#T)s2F z{=9_+p0t5W?Loz}@u8iq+HRf7{ahZXick<#be?~Xyv{8IIu6%0v)lM;#L@UUC8};_ znn?+!9@>z(a=6Oh!K)HhIAxO;IgOJ)MYNcZ`C68jN_6)z8tzR=t7)Lsheq`%V953x7Q*x&+PaeC* zw<*o*!X{McM4v(RN9zeUGAgPX9DK50Kw%z4WPZ*qpCEErqufx(=wZ;xB}L0S{P zhSTHbUb-)fsD90 z!ekl3xDQUvBt|-a8)sZ}ar3)xenO!Ax6q{Mz&h%}4@v^Evp53mkpftWyUL7jf8+6r zp`QEL2n%rz9^(+i=F7bKRW4UtnVy-cgd`p?Ga9P;`p>SpjOEIg{$85Zd-hisL@QU! z+>o@KaG77&yy7fv+wo(|3;&WR!B!uTW*E*9yEy>iypaEgudH-1PPn%Lk&- z(MmtwCp62_ZUQcClUh6c+b$C+dDh11m$FF~STc9{e%sN4UxLe$W1bq8@ zkMe-8Hg>}9#YP$61SvKr69Q?+mwgfTrYb>smm7Yd zU9-l`e(w=ED}qvci@zzyk-k-RObR#|%BV+?yCIiP+m|30oNuiNb8xF@J$R|niz+j7 zm2ZUQ?jn_js%=XV92`06b!54grZnzy`^07wjCs8AAMH9(Z^)xXFg);T945c8PG#)G zZ{fdt8xXpjADCa`@)5F4gl8zIf%R2(u;VSD+lB`A(=AsS%qienhIDWR>J2$})p=E3 zW!)Ub(c7X32f)or(TI>k)uZ((rAT?*1I>$`+M-W|(;y)<>5)MIQatn8>_Pd%{xyL+68lb#!?Dw?^ov)w%!4+?jpdT)ScV zy)3GmNp^$dJABUf%O<{9Qz7U7W&vN~bN&;Ia7AziI4TfT{zG{|#XP|K-y)J2n~lbO z&l}Ey%(z~w-;=$|=l1(ZXY|a)X94M7ez<)?LSi9K$MYHFrj)6usKl>4=Y0B~nEPNK zX9$xy|3C~K-fKU8HK$3Jd{|$bH9N6#pM++snW<9Kti7NmKNRe z8_2|l6E#x>`2~79#){S~aI62~hxnd*xP33q`;#e@iFd<~mw%*jLj!X15w4QU-W4N> zYw3Hg{^Bu*W^YW^O3bXafgjEq%5;%XJT@~L&$nb`BtVl8Qv-`kr9@~}vHI4+q;IU~ z@2rU2{q^Dlw7!&Agt=%KnQ5&K^L8^MBFJm&@R&fb%}f_mT|oqipZw+_d68~LIU=1igzZjt>Hx5`VZeY z1|-V_yI|D-6;W6i7kJp0M*k|)tY|Evu-S?G4!^w}CCczx6gWPrql@V_=zMaXhYGw> zD$^o|D37A|tv2cJSlv_}s>9>MyCcuw5-Ep{&_ z{53zC#)9o;s_1J;sZpW6=~;9OiZNpwbe^w>?Z*w4Z6tpu96ix5=p_!lNd~4euN!F z=(pvn;CJ{^9{+WT1CWT+^Qa9ZK5Ro!&5Zw0&28Pt&kWCO-nqO_t#_;^!jG%eR_6E4 zZ-*HMS7SkbE7Cd)i|o3Eyt;H9U%%--H;Yvv4;I3w!lw4*TLRUsGN3WCwe1R~!;K*% z5PcS1c$qQZ9{yv3HYRj&s|8BEOP+%mu%dWy6mF>Kf<{IQC3Hn!c%bnN3IW$%cD$wM zGLWYtbW)DR1(*dk8A2Sbxr35lIS&@8Yg$twppi;h6_dGtK| zlJCD?;$)Yy+NT_`@zjxk!|X&5x>=vTnG#mBpxr_avoneH1Gc`^-Q=+h)-XQ~6^wDk z&yh_I3~8AfNii$B*Bs0v92DMa$Hn4sdK2J&CcMedKEh)Hgl>ILZ$;x>xpKS-=@k$~ z!sNfxWNOJRwAx=X_IuhvmoO4y;EU0OKX)j7rHpvyaN{KiOI0IHXmU@=XIIdDSS<_? zm;Y|irXyd~bbYWU4K5;E?9Zu{EQ`XwF$czV)~kL!f>^@WJq;45*=VW&G~fTb6dqwd4wL(~X+p!#CmlgT%r za7N?SJUGmvJRTm#v6CO+$iXj-uJ{>4{`69g&2MYFBpG}`vQcCPdLc6u?c!R%wF`o9~6(WfcH9 zh9)76A9=lM)>#Xyao7?eBIkSbsrpKhb^CM6(DP$xcL>C~S@rD#k@o-0MSiz_SIUHz zI$!X@xPlMRUuu7dOIfLcs}hm7b8>PgeyEQ=!pZV-4>Xbh*bU@x2fRF&(Rv993y{yO za7P7b>pwYwB)A}!WO8Hbp6VFTMGk?sNzN-PQgd>-FJUBoI5Fe|&!`?fL}#~9R2Qbb z763!N2=%YtR1VemB+Y4&MA|tWRcf(t2lK1ZOcZt;v(KjBuH5l?=c1bqp{|TuhDQQoLV2k%_$=Ob2 z+rDP`LFsx0h%OACJ-yd-o34pFl{S?uUBCx@u!Zv44ByuTD9z@GddI=U&||uaR)pae z(Ylk6c<7ag6GKT*!GHqRU{TMdt8dewX?y(Q?)^pumRC9nLg;p#P`Pt6LmlOESZjN7 z=KFw6&_SS5qqiI=aFpexU;MkL=mQnV*DeF{3JM_(kT$B0Av0o=M}T<*y0khrMkjFx zXExQn=&(uDoBvK^4lQJ_^{q_IsOVAZ8>?7Dh#x=q?Vx=l>$lA`P`n*~JwdpCjB`Uy z90P#OGs8I>IFCpCg#C9}JG;8L3nfn5^LX<{>YWWYnescVFkqo@;Z2#oMk!lsTju98 zf!ShMP_Zf(G`Q-eJ0rvV%#!ZTW=M3BgtFYJqM*9BYa>lX9i z#uTOARW1iiFoGO#5#r}@>n>xkvNKvCHmDKJ@i6}-&-$dvn0nb=AO}v%aHY?La0luW zhC}X!_`p~C(U$GG%3YB88E2F9W@S`WukK@+r10CwX-k@p^Ir8EXiTTL)0B1aZ+{nM z(_w#2eS8F=%$*3sFC{krgm7R0+sHtJscoatJqauOx5H8CI1yat74~XY)x{`NC1@%A zNfQBpoCn+7oy+J3G1v{2$IzJiBt+r@6PZ{BML2F4@^P^sfT812<7pQxgXZR8c1-P6 zVb8y)pTup4E`MqzEYM2G$u3TniKIaG10|qSV*JGe0DXJ5qZ0v3!gVYbQU5%k`3+<& zC2np&>Ox!s%I?UQv%sdnm-oY$v#!CHH~sr^3FOP887whzjGl#c|NHXDCmhI^U;Gaq z7a5Nm2HHQ=un80K8EnmO=s697TzD^jB2e_sy8=CPgb*#8A1kAYy315uEP{MjPq9@B z(IXSxGNoTut^eHV0=2fQ(IpgxP;2{@Wz-dt@v-HnHTL%l8=%RK^nG;QD!lkE8$Fa= zk&y<3D4y$4O`;>HydupL8gypl5xNFZyKpim%S6=U4Wv4pu=zfc&x1AlkTacHR0MsAj zC-_x__n8>2)LmdSxkNKZRYXK&dgWm^rD({JOHaA+Suah@;ciFdb+t)iRksfZMknh^_iJBpOvo5 zyw2Wi-19`%5wf%YM$VN!BwUQZUw186>wp%Kv?12w= zg3N6}s!qfQ#vndWH@<0&s-fiFA;94 zG2wE_EM(#I+!UuJMC1N^dELIIxE>T2DLR+TJ_HPcvPJAc#sduC0)`NgA=^B{e~Jrs z)TN^q*--?!^1el`SEfx6qhbWvQT2&fQDjG}F}QZA2z^nR9mu>WK8ZN;gf`#d_z4xBVb=tvI-jV+Fz1dS>x z8ocGGU-!U3DM$=WRa-__0cYh5r=(==L}r^X`gKMRB*vSr`Y7&LjB>c?Gj9x@!x`b_ z(P%9gWwhW%H(2M9sT-F%lc(1^w))^~obU*rW|!*FMZ=Re9HFbt7V}Ml*Qcaj=S_!n z#1W!cu&Y=qZFs1U^ZB}qTmp7#9IqueemkJ#1Ct%j-djdx{qAM7xfU0e@hd#`Ezn)^ z1CrVoF9L#(JjDdc0@Gg|q3DH(-Mt8=-XJlciNJE^%Y`7mnjB(>|6tb}SS>mcpB5~q zvoDjuHwIcMF;&(;c=AilXJJRSEp8_T*l5P8 zYhf(>4o&gP|ByB?Sh*@xM~&g4(Do8BO(#(WWWXO_oSddcTvx&x7X+JCN}?J zM-|B{Zy4IW`W$Jl$Xq)BVYy^c8hg>G737EK1&#-(vhzso%ixusf+u~h!r%?2 z(j6f*hN~u+^;)oOXe=PzAT5k;J{-UK@#Dvikp9K_!vsJH2p`|^^Lv-}h~x*3kqCVC z>5_G*r?Ck8Sv}ctFFPb4&r@AQV10npNYoWekU3zB9Do}PGZ*voMY!YUN^`ns122V;J3Pq1vx0?s1 z{t!d!i13xCYdWRo9jG?`Ep(v$ypnyHE0h$)PEeQf_mE%NmgM6uy$5Ng*ktfwlsO=05Gqaq$01gpSHLFW@{LNASDWA)IeaA)xJti7PE?nPc0abCdeGZF~ zG9{Tj1@F`UfDZv`N%ZiNHj~BMENxWkbrITYR=rNhAiU}mK+X&U_HpMGT@=m^TSVoD zLzB0p**%(VH@0!$`xR>Lb>&YH$*RDr?GR(g9z24Nr1ley$QM*IzU|HDy15<;At^46UART%`|0SK_j#>fMpqY%$T1OH} zr$_m1WGKjBb)0+BL4=3!F}Al*8pd{$6I2Sf!36%loy`5aF+eAlEc16RtQo$=3Mr75 zn1ACUOo}Spmsa0VsPSWaF(06E|AF?pTP~JK3b%vu5UN z4Wp+Of9RpPG52DZYs4e&(37LeBRGmyJ`hvk4N22yc@&G9X|?eo!fm3v{(q_h+>SN5 z-IN41CsT$^o8)jUf)ARPgM1hw0vc$2;kYWK;kd|}BLyFZ_2G6S0m8O9Aut&)CLg%) z&O`k7REqdN0Zyh_P^t+1SuEYt-6;|F5RdcIyr;s?X)*n$i;s2mSB(a2dR|W{KL9s@ z8RcQMoTZ(hCvpsw`>VijRMOrq8}b(Bv49=~6z)~;`={9?V*3(=0$CP9Q30c}Ie|5G z%RY#W`xsSw6*_h}bB^H6Zb2R-^jLBYUgu8?n^iC|M-o3bh0AtF{{=9%_@?t}5L`9> zA*P^Mb|z}*z3wSK(f^d1%H}BR&jHM@4vjc2bT_rflBK^=?s`8^!hQQL2L{s=H^-mY z8SBD#^_^AcN39ow6~?uHbe%Rd0bP9jBh|UGvBXa?w$dgEdud5a>Tf!Te996L5e40u zZ~eRJM(l4sqt}EOO7GCqG_GFC5eo8d@F*1PLgBbnKuCPm@6%_$+ek$f=+SXo0y>TAjCY5r;BU`fZpv9aU^ePNwwjFOY z`*;~H9n)X-A|PKaMYK==C=#s;9J4p(f4G0bS4d$MeLP1u_az7D$Nu4#;5Yo9Kp50A zVunPH63hzka}Wz?!NfC6DR5KP4-ax-b#Ov`FOuJbX%$ABMCw4j*Mh_dUiLJcJ0+#f zs{tVj8<5%o6IBpzyWlY)LBoS$yGPx`B*02pJhwwqcJq|j-jI@9<@$RzZG*qhNuLmI zRu!hOv6FVa%02^B9fH+(5BXXv4QPu)jnxZqz^@h>eA6~|QvOe2aBBr7#i0F5I|GD9 zhd#{|>l=vW`XKz{6Yu2beEOS=RNyhS5s&G8^%*8QKT*mXc*3)Rk>7*07iUfio1igb z8uaCBv*;(m|HF@`@RU_pPFxvbpG)Ut2iv7Cr<7cJ*6Wy^#v+id>GM>XD)IiEGMT#T ztM(I359fZ*efq~2rPf5v=i+m_X>08DbMAQ3JpKjTH9xUKvOnGZAU!j;=ffrrZt?Kj#1gf> z_uR9Y_v$iv|Lt_O@u-Vny|d5lb^Ao%Fb2Uy7&y;WiHUv{@&TsUlB1B+J}CqQ`c^>X zQm@ihB$W;MV*0@vfbd+8%>Ms;@icsK)p@e?6Pb+n2gP?LH-y<+5PIStHd3y6H!U9u z++rspFtl!;bN_}EoL~~N*gh}#3BCV9>d;4KmAC{{YQPc?J~b-IW8hv6@4EYm=)n@j z%6$D1w^^ofT_);3-whF{oy7A8+oBMTDnfJC``#3Ar)n?E0z7I*@)Mx$GUTZ)9(9w# zZOG6*3Si!&9O0&%#y}$^M35d#(_xBXVbd5k+h7m)=q~v2U#i}%%55JjvXyd`g384} z+xbiatw3DaILW@q4>Y?anZ%91wJWYC@t zZun#&8v6HBPklwfWQD!BFxA>RFefJQqH?3$(`+6 zGff#Z|I@(+o>?uMc(7x(N_897-)eA~u>bE+X@!RfzWY2`ra?yk!McQb4nX<_>U{H1 zBA|wdR3De4UEHyE+(%;}7!A`0g zoHw+Z=1`*JAwZ2>Sz4T;T|~ifU7Gn0hDw-Lud}A?wdqr<(n1(9NZvMg~Kj}MkXfQ$P_}{{4kEfunM01Zl)Vt-RNA=N9Ju2Gz*fK=Oh&x$z}R6 z`3QZ8(8w@FNEJvsGH#j9rE#Y`j$Fty6z*evs#0=&SYmXhb?KL;x3Bl;tL?z=t0&&x z`t6&ULWWKa#aBW@)o{^(S=1mIw{u4s2R#P6E4*#s88B?sL4wXE2UZ#A8q7*UcbrFI z1F9ke!ZA+rF;jjbtq*w!Z`BsAW}%}Su!Thzf6t9}2#t@@7t?>sQt(?3M2;yPKe+vn zWGi~AWWqvEDikkoU_g!#1Ax5y%WUBEE6*yL7#PqJv0K8hddR^m5g~fSp!OyD{)gs9 zqh*EndPl|L_ur-gRZRDN`X)T0tE$1s;6n; z%VkN)$rM-Axv({|q}8W=ob1Ll)-L35O#;Q24?hNRasyLmY>?*LKR4!~y8n}+^_Jb& zeBh<$dV1{q0bU^Yshuh#dko{$a-ze&%-(JrJshDa9AWPwfzf63C#+%7Y+d)?0#Bu8 z#;+`QuXM3#p6TcQdbj64rY^fNoB|Th0la@tI6&&+C`3T!tp`=hMo8i>5pYW^`edu; zO&xMlG$aN;4gmi-5%5} z_;Jh+j^1z>Iyc!Xf`Hzr|MYAqv$UgJyWrvbEBNU&s0ZJT2{+x|NHgsFs54^1^+1Gi zc8@X0!^0MFep;5hXWrF;UwR3Qvs1<$5zh3>L}>`>BTWP}?vNT3toTmSQ?~Fd_YD

J!5;tc0a7F2_om*_Q)%8I#RlTXf~+jc@hd24&5lUV>&CEZb>U=O?pzshqrvs4 zw^S&dl;lx`zFHfdTR6V7Uh`dqvt6SpP7LvyymD>`h@cLkAbOu*g4o$oc^trBi2J!45wYmxRl`C@pUE z<$Gm48EP(@B>oUOoOJ-;U7M`E4sxJl{&pleG7KZ~{qlFD+ai(d_**$L?VJcdIO6{m zuTVl%f6c0WqmhVU%ij;E73y3j`Kf`d9TOY7$uQ=HArrf)XF>+Twd{;45FDSXcm6Uk zkPQ8{*N3`QOG@H?WUc8LuwdVKvVXgljGK*#M)>;%ocioy@)X!@53mX19^D|BIaz{B=S2B*9IMyU_BF_Z`{aA1K2P`~GJ9a*(k7&6g+T{AxV9+jot z)ekGQlD(%+n(>^Xa%;Sbflk<6`pXo^zybTk^BO)+^c}`p-)3tXtM=Pl$jM@R^RlO0 zfrwNLHY+e%%n4Rg%>pk~jFRiI9T^@K$73h#)ugQdMjB80j0uV=^;)$Wz`o8 zs`&EZ2R%fu9k%3{&e=u`e=c%Eqrg`h*xC}QVV-_#<`wBIaJR34TI=zjKO9{)>WuU@ z`*FUmvg+^pe{dm7tb`>3PZZ`2Asbpn3XTMlo`?R@`~;h4;|mP$wO!s zC#q!{cM&$O<=jBc$xKdI+7}v+iHBJnxeP{i+sBKxC$4iAc+DQBoEzDWh4~9Z z^I-kSOg8w!PLkb;@GOoNKKR1=Me4ur-8nLv{ggR>Tjfx!>ds_#w50y~LRk$Gh)jzS zxT?3_D}zJ?6=U0zu9Ng7MOu927bf|-)ZhI(yGKW*a3s2rBJ7t>B$^PC+?PIGC$5cy zoqW$g@{SlRXdrlkdiw-wNWJ42A*f)!R4(p{g}kKeeC+Q8zDS1)SG>QwACLU}^&p?|}K|x{in*U#lo%|11{&Y%7@xcsmm22NH{{oG_+dp0{Ljl%f91Jt8cp8);mLzqI* znm&GFDJS0j6SL7pTHUXofoJMy_K9X7d2&HY>r&nFP}S^T)*QEy=Vg%uR0#X5-wk$C zPM`tNKxAE@XHGuJ!ouPRs7+EDn)RN=XUj6;4oOCO?sM&!p!>nd#?BrW9CF_eg7|VE z>pY>%FC_1X#52;Yc?Qgy3?s2c4=7=a@nDOK-7hB~x?Nza1kZ*3`FugtT*U~CETD=% zBE(`m&?>I8nS8B~ zmce`#c|!AoGsHl#N$5FYZ)X=L`sqJ1BYGbKyk}h84T$DHQc(>sv<4m55N>K^3m1^i zmTEBsoUE2+1XB^m;12kGR7dV^ZY*v(I=n1=cv(~K3dpD)7u;PHOr8wmM6Q1?YmmOX zzlhbJX$lE)ibt!=^8jrNb& zt^1LxAaxdq6-9Tf%gH3tfW{_Bqq#uCSP#};+qA@a9+{6vqQHQF_hmxD!bUNF5cR=I zpM|QcJ1KcF4X1#FK#JX>9t$zLsV?!8EbOG?q+*uj;7`9Z6yO_zSiqkvbO0MQ zju?g8np;c!zzD3F(KLHw)*GI*mDxYlZ_Y9x;U#5Y&;o@>-K5nVcrt3)t?wuyKllqN z2%;!52r3YqtgQ0pEOBM{C>;z&A+1`6AHMd2n`iFVGLC;qsd93nygA<-JM`@EalS^@ zFu)Z>%keY$A+uEiEnYzgxW`+_7LO_~GW^QS*mCdGfoUS$8f)U8bd+ zy5HCpJ3??f2QKRQh$z_r)a15}b2;$A1>u9)_qhD5M=gQ<-~NB3?{5J*36nQgQMyjx zPdd^?3JMB(P!c3D*b_UEZ#n9&l#;=Z^nw zlyigLskKS9MY!&Cj_)idqKVqe)wK^de4jbEDfhPXSWFeKixN~l<-zS20|DK4rmAyh z_PS0tlFhfT@2aFq@#%1>C6}p|UZ7I%V@0W4M?PD~pZ5XCD=|#~Z`-J|-~^YV_=NJx zMQ{A%o`4FXRl?;qUP%YAB)Q2WMRZgFzBdc<%}yjF9AvP!w-ERKh(#3*jgSKi^wh~N z=k};2GXLA>H`KNu@G60{Nc~>Y&H_tGqyr5ZS+P!HQoMq=@KWJ{j@dxi`0bxWwaxlv z+A@EnL`6;3U&iw=pmbOZt?a8~VHWSrlb%qiOw}`eD@8vx(OJ9uTiJ)_xMZXEzLv{QqEFCCI4%Y0DbX%IujK`;=!Lsbai ztZ*wN&_$uWY@P;oPf>lYoR^k|ymuRrz7Xl4AU}T^;8v9&UZ);=_ST_8&Wt`_3t_;q z5@p>=*fXd!6=9m{`uus#Q8D~Ig!3s59&Nx)ee6M^u$`sC=25e18j+jswLPpF{J(*W zpo+Oju`}!;_x)9FIdQ)q3eEIA2zfN{X~v;|s3{-FAOmcJFM}<@(jZnOh5J0pN~+BP zcOx3Q?MH;lq>w58l!Se59O$3nwxvKq=<(Vq)3?Cxi_*OTL}gPAu4<6HkCZT9FJ`9C z4jWwk4JJSfrmmO{rQFVH?11lRq0fMiwihl>NDyI=Sg(eITXxP~*Cs0!R?PX^nmxBFT41n0310 z&i3zH!Dz@a>XWm8*n?(auJRW~6m zEsvrm07`~;FsT_7)E%x0o9_q?hHUNtmUmH%*XIL5ic0I>`M!&gVE0dM>FBT31HWey z-^czNg}NGMngb_i))!^O4xe;jIKicKMhMPQoH39C2)05)I)m?!5wpN)cQQBtY)BQpMBJR=Q58fMDn#cv)JsU< zA#w;kYpcOFXeHo%3JMPH>^_Ck!I~Y1m8{SRCRZA=PEz-bVgg2bp3RWxL`dm63Rh(& zk;vh;w-hp%!NCr0trH`r_dkz`K&{h$C6?F*N#%AUmHO^r&C5ud=Zg7i#vB5bBiZMj z;O5Ya^L+q>tXc6`$x?jPVhlSH><7g2F#kZ9Bm6)XKmf;APsA|ALBS|B;H?O4cxXq+2Io@NYUpRcAs*3m8v@y*L)Lr`{@EG+AHi<&JY7uW|O>TT$-+-2BS zG5d&H@WY}=x~G}1Z}3aw-(%?KM;^l$x(&rWB)lE|P5e(8=+U*YcMjxhaG1PKbD1Gf zU+c^@frS0d@KqymE7@zM0QfH=;8Id=!-K!yh5Y@che%c~iafTYYJG!6-v2zd|LgDn zA%<1P;3m>lSnfa{0SQW=uTWDKRXRFf-Txpqc!k`<5CX+8mE0@b?h|_ zv=?+HeQ$^Rxo4z%?=rD3?A5mB_lfve`InuIj1)WiatJCN>!Oduab>bhX4 z96%QxQBmo!@T$?DtC6?sh@8IPK(X1oX{=6kDyer>GuA(an1M!vKoPrmic8^M{--Vspe=GEFkqNjUaLwqBFzLvngZ&#v?BDtg z_sL6IAUJTJb*My*Vem-BT-QLer1xNXz(_Km`ESvN=LknL+wqg%y`j{n#Do)djwBj6 zqWW)MfZ734o9DXQP~lNgh9NqsKvXm9-w}Bx`IcgnCDc^eHuO{;C0c(L>~*r^7jTn( z!glan?}X@NYYl74)0La;hq`W$2b&IOnaP&gY}d-%@9X91ZZX`MjL8(ZfM*|!A!1np zJcE9P!|2P5KdQZ5T}mPbM(9T|?JJbq)4)B@S$nz4`CGos<+s#fS?*V!-=OdZGHnJu zilahecxFOy|9welZ(K&JCH|>Xjo`!~iPq6emt-0GU2Rk0z?I~X7ji3O%-mG-?v1K~ z=ZzQQ^$Lr4M>&N7x_v3F{x6l&f61UD1Kq~8b~>7xNgTJ?*%f2{RL)v|`*N6nOI?@L zs+}^a4o>vE<{|UZ4a2Ki$z__Q=cwE@gR9(nby815vLu_TV?wl!RT{@;3dDUr^LhW)7%6Jc>ZgUPl%H_UbKR(5nU{EwcM+Xtu+Zs^u ze)p^IE|hdv!XSPlccg>!Wv(&B>WF+`dY^A9Q>6M4v+qT`3&~U4NW;QAyw`PdREaR< zPZKr-OoBtuT$|qKdU#y;dvI^kXwnr0ev>Qc6F27R*}aKIuit0x@J8GDJ0flXD2tLd z7?)s*ZhfaD++o!nAzp6=Gy|&}lXnM_&oVkeuN)B-dN~DEnW$dwrw54tJBWL(!wEMy z9t>#{4&J168y<#{vUS1vP_dd`fh?v;%h{o_Fz@%|Xg1zeC&LEn!Sm=BRSv699UHCJ zYU^&TRHboa&uB1KnQ}2bmQciny+{ z>qI1_)AYyZJPCs&%6B~PFit1Exnv2R_+h|2As5iWL=W4IRh zP*myYvznO(Cqr<*{GSz{NQ=#@B8Afd_cYvPvZUG+`J+bN~@FQ?*(d1 zzL<=#_|Psjj7K$`X7Cu-L?Y7fq}qTeekR~Zyc2J(M6*SdR7QD9nOwJ=dH~K&Rqnm- zwk9CK3=glUF|y+ov5bpo#T=g1Y`af|oUBg0-EU3LTWwDqRuHU7FlQabsgw)lo{?9t zjXii1C;#XwxIk*iZ>yM0N%7GYS#EkRshSmr%?KvgTz#HNx|by z!g$VWh^hn>gE~lEoXiMW*b`Pm0tY4kEF6*U^$G8OX*uZBFwhn*_6dku8_AJl3#z-I z?#;F6Y-@6mUZiT=o3fTM3A|BL41GA>G2@y^eW+TYY_Dm(c@p|bf?0~lbHlvJM?+kS z77BQd+W)Or_q5bvShZ78i6l31Pubi3$iJuZ+;Ois*|T&`{Fl!!zqPuqo`%wr#$nfa zw}|hQ5162?i-P2c4@=w>58aNrjX;4;)Qd5fW<=1?L0%pM&|GnTmCC$Aa5;uXOI?%- z{|=5^7TA=R>goTx{Q9+G`P9hUA-!GB0@tg7uYwgTk6;4lUo;YM@Y3N?Yilc|{||6O z=zX%+n=TRGp;cB>BSE$CxvM_m;Uv$hxYyL6<|?QDE>fjO{je~&yteflop~aAUWFIl z*L(fUB|@oMDZXE!3Lie*O7ZwhRb;F0Rq59^i2k{oJjr_%(YocjZ1W%4EiElED?23$ zFA)#Z{>=Ofgv&*sCB)$x0OQ!Jpk%FoNC$nRq_XZ{_16v;>jydeJIDTBgAwbtQ4813 z9BC$_=&ywm|HW zvkFL;80LHi0Xs~x{(x30#I%B{YxuCEqvP9$qggdzDJp`}$@_bPHvo2U6RChN?Qxo5 zpx-9~z%ioiI)wOVK)q5dg6^Lx&)R}P!3{HvkFyHeSlv*o*D7VzE*IikYDwH_8Ejcl zE7}UkE4<9@|AW#xFFIvC?E9xrT%K+NXYL_e%h80OSB)#{*Q4G-iPpNg&VK*B zy*(0^>kPsBgR(U7NczL1ITe3+z;(5#3@`9Sb(7%+#!E6?bG*A2k)G({)g9yG_b2voRq9H2_4cn=A2M zx_|Dhgoyl}LQkV?E_SW5`+QsJ2R;J_9eR=f>9ICzX zREJRZUl<=eJqX!sX98BMlzP$CFb40wv0k11iG8m!sdNj$le>YZ9~4TU5BZ^>dTEZr^?py)~m$wWUmW@buCa z(TyVhAVvBQ;t;cA2b24rPKB%A;|!y3oznhAZRPW5fD%odGl=-!7pk0-_s2)Bo{69dH#c|r))=*S0l73YgavmcDo}>1T zDiI^R9T!F*AAtm0=ch>CWsq%H0kjZV6A(MTGot+F(?8rwxFMl261ccyU;Zh%Szg4< z)M3nceLds8Y?UGH>V`m)nl$6>+xqHX>H%c&Knl?ziPB%OQTs_tr~VT&#veZd*lRiJ zy;p~#{*dgP(foVwTidPY5`B^qvZB8}oiRJe){_~98Hf(NyHB`9R9VX}*T1ph^5)VG zuoe^ultKwyz+*vqUSZQ;PMyQyYK{er4^5!zoR@EK9r5TGk!%Y@mv&M4FSo{J51)gG zG#^w~)F{802ZKE~NN5;vyG`)q*D~YmBLW6Z_*cDon5W=$$q`<9t7}T0GK^Aa5Gl=pZFZ$Rlt!M8577gi7cg@!$(;b zS)Ki`EiD-?y(Of*)DOykl~ zOd-|N+g)Ir`A!50#D9kwJ?6f7Q(FM4>DQ7O)Q_X=vT3D7gkt-HQ+|05o=2^;>^nRi z)12E)*MOk65Yh}1zBp45WkUDAb?a8A$oXQTx%kd|j|m7bD>NX@sQ;Th77<4I#Sdv+ z0Kuhp7#5#w6VQ}DID^q8GIZ5&b$VgglFNi_9L$SL-fN*{IT%lbh34j}udgg-q4nST znUIe0?aPxP-e=UEe2K{Xia38?!;T>Z$Y@i<=d-Z8=p~#st*_acc=*KC;s30vnQaWD zBhSkilZ&Ex6evFz^fly3>E}8B4PXZ-hm{rN-*jOXyZ(H>^ZoTM1sWT`cL&QknvUA) z^$2yiR)V4m@vzVXwEvDp#Msllz0wf{M^^%}RI{Y_UE;u;EKF-exDS*tFV-iyAck&UP{CoVNPNUjv z?*(`mMX_b?r_jzBq+e8dUJ;9EYntm;V1LF zy1H7{uwXf3BlPcqq0TmNrukA!g)}R<{%nVWCvCYQ-r34D?Ucvjt*VjNB||Es20Bz1 z%C|Eat1@x(A8*=X`!xobDW^~v9kWLx?i1WezQFy77`haGUBzE4R-h*cu zci!%^?Avt;_W||i6p{O(Z-mmD8foAu6vHDR81KK7&O?W0k7CLxxY^AVK5${GdC~Z8 zWKM+Y+89A_!ux4do$?(RWRiiZSw5%|Amv8F^+1TAIs&$wt)bFz35^D#K|$g_m@vBk z^LWK~Ygz?JSNUodkr67GbJ1M*g?VAbv$OE|A)@TL^@UmI2?b7&jM@t0=8kON+RGqG zd%_GpqE}nY2-+j%VcYrN(^v}Cqn(}9c6!P=`f$?sird5PM>ocHUiNqq)ECiWvJ zWB)xD%`gOVXB+@_4mjMv9W-iWdD8gyQe`J89nQzuYq9$(32~2S72eatWPPJ+ zRN_|eX_k*j@&b!$LTUg7!h>=F+YepDGT8WltSHfDHwrSeto68~A?6QB^(rskcHkLn{9uA?h6TVDMzlK)zIO_e;7_ zqX*j#2TKU0ySH_Cp1IxcF_6JU2&!LYl0PMQ7@Qh&HP!Na#=-u!=Uc_-ZYOt(SjK>( z+=H5D*iG4l+QVO#qMH9;atV5pXp@jEv0F}$9rWDuI()Pc-!J$D{)a!0sB?HW0A2;|>aCk-e!sl(f?+Uto^dhcSKD^IH3(z>>9aByS%G{}p= zN%!-I17mU+@DsPCaH|mGx!a&lCB9OF){W3+a{=l@V^LG!^DqX2YkV#^VY=^MSCpl!n;g!0G?P*I$NJxkhcHupmlFhk!68q(MMILQ*;=At0q7U;u&= z(%s!4h)8z`NC-+xNGLHWk!}#ALqhhr*YiH#-ao#*f3D+jF|YfI5$8C^If5w7WEL~% z1lNCv1}-#n(&E>ScS(Akihx?Ge!V`>pE4uRzGxKljFp;8ff!{rmhX{y8D=%YoGxL# zjyawCoVq&1rNiM;){RL#O2_D#>Uf0v-qqFB%7(K2$_x`?_8lw9s8&@o3X=Or>4x%x zn)ybZ`|B~;!w=^Y>o=Ic3{otL)#)BWiBuh#Q~u#SO!(FJ`z}(|0mwBT0 z8AwUp*LO|v4hSB|vfrwFr8zBoo>P*lX8CI%YrS&s;n2Imaon%;6t=nX-?crruWBao znNSnP5!2oZfMMf*YNhFg#If|uTDKwvT`#^#d#iFc{v}aZOm*Qay%cq4+|f6~;$yma zSbBfR;PN*uG}teOadeH2A_Mif@~U}qEK+ZAApd^``gX%lDK<}8!oG;4#`mQ?4Qd*S zjU{7U+OO=IPGHt&PB6+X#Dz$-u}@?inKDi%U>0C+1rsLr+9)(QPX5b7kb3U#zx2Eh zlzpx*{KXicB$}Z56|A@W7y6zFTBb}d^IcbisbYYg^p`dLQ{$VKmghfP9IvihpuI`TP)>rmtX*5dSIe!vs z7#hsjHA_h&(&9&C)UPjs4dr-INl&d4AwKOgS*)<3>w|HdVvlM@$;vYF@eM`ZDS-Sk4= zYaUMKS9U=EjCf(7XVE_!l_2}`e$D2;n9D=Aol+BOS_-o83+fbMTCdjW2Iy1d+_(Mo za zhetWwRnxQww<;^%b8ALsk-tn}2d1iUK`@r?lakEu_2T<4KLd7L%qFLMj`d@JrF5j$ z1vqW|wd5%@-J@s9lnpW@Ua!R5cLAWI{j)|l){QG@un{v!5HlQJHM!~_Tj$;CSq}j* z-RH??{Qp#z(ghckp0B0rt zO5;`tf36Vl;VhEJcY{pK$!%HL^sAOR`?cP6;(A+@AAwp=aTqJkzV0OQM}JI1LnGhE=YqhdC-md3+cSbR>SKBE zA*CyhRR%)7z}O&*{x~Z-=}I<^NE0WtWN*3-EkWBUjBrqMtgD?ty4jb)0&+@v1lLxI z6Vl#up}(dCNTK`mR#+k>_~jU|^u&JtRb6nkaQ)B^QoY>yF55Rz5}oOv&2QhqayDaT zWexQ6_m7;kjW_6H?oBp-w6Y%gOFQ;kf16Y6qt#IR_fPmQ-KkY>e(#Q>=Q!U%RKYe3 zrOkvCS3^o;OgGY35)`nFS4&56T7Bu{1XK%DSP0*B%XI|=lSjUPIPD}K;RrSCX!QNQE$A;Xn!jzb*D;D$xj zT^#)*WX4q6$}wb(VSguF)0bt^1eI#GO{BUzn^S^MNZ)}OV4t(vdJN3>5skk`yJ0APjzkb9SgIFIT@Z>iCzC>Od;z?z}(C{A}B-o*txemHCx zo@5)_483XX>~X0Q&?x|2Z)6qHRMF*S29_cr@pHTmu)~R4tim# znND-pLo4JY>-=Z9_I{9Mon3Q|$itPr_S*`VYnKO0=>7Vs&~B1e{mdvRF(hh>cZY7y zpZ*lMV@?hqBmOzE-R+lOTrx^oGQCfVLD9YJRZ?sDAF9s#8-tNK<(Cv{HKe~wv^G+s zGR&_<>;lF%0G-L#w^N}H?g^K{#~jZGIYbK5Hfl&k83=}5UTzH_Ca48<6rvG(hh%rr zU2!6b9lxr`E-CK@7Fkzy_r|7FNzW9RQ_2Z5O`sc@E3X$GAFA%QRxq=jo!4R=S{v_e*rl3mRh&tgC8 zH4!{2DJ(JhJ5l}dL5v2zTHOlsttXKB+4_RPzskr&h&P5;V%%V8P|*P60fwLi4_a@D z8-iYwh*AOC_HymI+<4|h?7QQoo{GRo-MmCziIFTEvI_>|1^0w)ycJ z-?0AyTP=*LyAYJrLO31n$;u|0E7AD-j3>{m#NJrf?hMRq@zyRC-CgkD>^`#zLN18NLw!NeCC1urvs;HZ&Ah& zfO;K9anRTu`t-^qBIH5HO1wzSDNBR9Re@w;VL`6Bju zu&@byfdZfn2}ir1PQC3U^gx94nS=5UI~1S$e&Fe$)F(9@)FU&h)+r}@JsESDB+|B- ziD(5AurFR@8vm_eJb0WNeBr|7BxN}nop)gq8&B?jTmmUA(C2vB=j#S39l3^MvqPxa zZDO#Cepj95SN~I{fDsn;(R4xt7#2>s`gddAXYMJ^Zi17&XZg!cEJ7(k69Q>ga(W|` zhC{hbSk8aQ4wj^=KINN6y|y#+JNMd35kW+lvHeHoXay}|^hec1Ljsm?^5{2Z6*0sX z#?i%83ESa06?HG3nod&ag)&_S2UrYu`-=*}U+Eb>Y>12~9GGAx`x_+HzKKGBG63}W zm<7&gzW<=w;Cue4e_~MatC9Bdig8_f?lFK&oyedw(hZ^f4>p(DSK&LYA+8sEF~T!f zXn*wYD<)SQ23tjaoJ-EZnTW(c_=^a6L8VEh2bm6Q-WkOi_=w(WD;zox!rK zFUer^L)#z;d%pI5#s#+~)62SHVOuvZ4E-U){xik0&JC(~8eflA=Q?o04^D@dfQ?E; zgK#jlIZT<{FNH3J0;R_C-aY5;t~2(p2geL7g~k>Xv}(RY5aX~RK=l)1d50?Y=HgnY zX!=7kB$vo-e&Y>$h%Ax-{q0ezbAA6N{r!iZt$s3+xhsH`>PVHiqG(7rc4zn()a~y6 zjG}9Rp?m@#)1)jxPOO49T-wgu?>wl?uv*1ZkPp?Tz4SQE>Qbm41v`cqX$uvxWvs`>e?=L>;>lom_aHP#O%v+WIvV?2QtuUJe^O*Goz<|67ctAM?iVdI!s zadNy?E%{QOeCOfur;RV`Y7$Xi zZgx^_aT~{-x1if-3CXIExJ90XK!B(fm4C4KMJqXd-V)6?-gAxQgZ@&edQG<5kN0;K z2L=YB)Mt|yaKynE+9Dg7xC<9IL_e9y#CJR<$)hLk*H5|3J*BWHuruf zxcuG5ekxnV=hGI0D{dEEE<~Tz5E)S6EkR3x=tO~>fDYDRsgbaNO_BWtd^G-(W!Oe% zdqxKJ$$U$RKq}O#iEq%fXtc_)nao(h!D3o!;oeGE zbu+UH6C_jR9M-|lF7625MT2~oowo!71r(+7yw6Xj_r9@2_d_Hikks%av&H0(y2Mn{ zk13H%hwpN^o?k6(6P-D4F)AE>)Amp7D0Q|9P4-Vqr*z@$waK^X0;knr z&Tq>jf|u3#zBz;5fh6PQpZl-be=&X!dK*Z(^+aupxk{YR&dI5!Ahzjq@~x)??QIz> z#vz2Sr4nNfq{f{VcPA`|8?_rkTmjCm!{kF$zDL+VL7{hxZ?GiZ-(LPC{xdDdXTQrFNX4a-0g?qAoiQAe$X$MJ z@rK;xWk0yM)#a~WI6vQa?e1m>y}m*r*V342Mj3ACJ4FVk`(MF7T)k$3H^@<*Z0og} z^{*OquW35)N{gaGLP)bDMv6GQDUQ?oy1R1B>*gdh0-Fg_Ols|dK1|oESia?4*t{BZ zBAk6AaX&m~2g_MAG44<^@_scZ7k`aUCg}ztqrfnh#x#qyE#vqvC7Mk=5Mf5)I~eq` zY%IU0lMlumyqGFq@zGzSy^CV`EyNy404^jMzO)SsZ-J#8hPokr?IPnJpQ=JDPlnR& z%CUfXM@V4MPIP^r9*&bPLR2A7zVz|MWFbgul`sy9p(5ljj@-iHH8X=IBVY?Cf(RIC zjI69|d+Nb(u^#Sgh{xDL&fr>e#mkfxb@5t5DmiyO<*r1Hp5&O~+>y$l<*M_(bXCjw zT-}8D6OHgv(=n+6hu3`D_w~bfwAhfiZh?L4{KAC`=jRvFf2{tmT+RA>TpvpLsrKom zW^C>+3-pvX%yB4^XRmOyW_lFRkjiV?|1j;!$l~bw8h=+#gY1&L<^q3qaE4EY&o^dK zo^q@^--U-ozL%@5yj`6rlXzt%rZWtZR6m>=Rtv-I>x6Atu*hTZQ^j4$K`TlIJU=1~ zDQMAup{}luM%4ZWkbZ79BxyX8p~8kqCo_t%TpTvqT~K281HH_L7#F9_sYvMlV`O5& zf);3LNM8hPq7#EPq)8+KrtcbC;$W2uRzM?e1dRZ;tE=mM{XX&CD=3#4ES7su-Z7Em z=~2kH-`xA#5qNlbbe&v?Co%YM>5nXh_9{~Mc1$EQ=?7H8!69IxG?E@7UjP0+2i7|! z2np`WC&36iYM}OpL`5~O&^WJXNWVa@TqiT)QGWbt>Xp8|#T}<*8*W#Q^+T%p;!KD3 z=K~yzYvsRZ0&hrT-ykLS<)Ay5eLOGZ#J&aDs2Rxe4SxT`|6AB*JOBV4Jczq%+*g9y z6u(Z9uIIhfDU+c>yKDDI|4B7=i@ElsWe=xns0|w9STFv8!AkAs(Gt(xsMlviv12X# z@*2)`C__;RgLqHImzS4SP5$NP<(UC(J|r|$%aFGZ6XJtP=`Z+Qaz_r^=%euC{fgYN z*e{}O+68oetue-i)#Hku-1KNIUTH1$Kn%2C` z*s)fAd7g4dXlJ_|H%+=2K1^dl0Up4xU!fC`RTl$qA_Br3=p|MuUUa1+?N_Csd;MNF zNO{KMpUkPP6+_MP%eD^_Hs74zZyRY}G1KBMl%z|r^5s^Y4k!wBJWcDli0p6%E*9N^ zo944?@E=(C{pBPfow2z4D4l^S;ZMDLBmQ-k<<5Q=gk%^JZe#?p!Bof`tI0#F6&cGt zR`dxdfjx$H_9N(mU*G~*j>Zq|IS zxx$qqi}81QFBDc<>IKJc%lM>Z5UY@Ds#2(+PeL6J=8E!&RGs`c(f6czB{+!kb1eCm zs-Orqy1nUrZuDVpP?fJ8#(inkSR1%rCp;$WH=;O}?|9S7+ALsEyWqlrALE09pZYEH z)+XixKF*Eicey?;^sfB{$YpZq{>~wRleG;wQYN$k!8|74AM*k>c*$B6<8s}GiR7Bv z6fJ5ex4uZq=JMsu4|JwAvpf>x-eB&-#QLPTX^z{Nm}{(rHvX0k;M{ofko#?LIPH2JyQP>K0cSrd?&iViB4x{yj&Sy0T(n5?l*q zS$h99oRsfyasl!_L7w_!E@W_^DX_*IHnjWD(;(y&cP+ZExNYTCSPU@p7}x7h=|Ve) zT8bb(^y9`JR%GyERa)NrWnu7z9NW;cHQ&-C=C@b37iApDKOX0eA5D{yzGuhZHVydS z_&k8On8=6u2l-5lS0ZavD4Iu_TkRCk0M61k%kt9A7HAh|3E&?e=OR){b{Mp<>vb~& zMP!wD@6fTZN;O#Jw{I?3u*z{{m3Op$k3N6%-(9ol;(=9eg8-KKRK4rYO@Z_V7sHPa z>+Io0fsCpG+TtqjiwF0lRnbScHnIu&vbx9Zl>YAG*14Cys-yZEd}T?y@)p@Vf#KT! zY$TXRGZ+oKQ&vSzPJV;p95BQOaKeP~KD2^NpVQvG3kL~qQxFard>+U#?expWRH40x znF-#-jXf7$Sl|e}ix=qR{djm6tne-}Lg=0S3@+A#Nfa>ALGugTqMAw8{5|n9`R8->NmS4we*vk-PhPMxn zh7~iin^Rp-3|hh~Lxu6kg7I*A^FpB}Z4NrgFp@EtzMVot+!x%el2@N!4UWj=;WvCQ z*s;h%A}$b}d^_5<0)tJ3xAjcZ7XC zle!<3IvaSZrHjcQi^n*B%pk;)0OQ379{`$=0nid?n*0%R?j3{w8v^}-aV-g!KxhtSSy!()2PZ~)|0M>ihlMcgHxrC83}KFb76C!T%3vUL(@l$eKxE&DTDZB;qJZGr*dM zXTKRDYi2~&Jo9t!ekH8A_P;gnS~($Wu6}X#G6{-@kBtVXvJ$S-(6kChI4Z`+Kxlir z^Sb#`@7tYwZGg?bQ9A*4nLLdEABh6EA#fVnpBkbGrW?Wvn#3N}spxi9UDal_!vy<~ zfz5l%hmn+$GC7`5Qc}`1B~TU~;6lVY+$+802)op~cFD(cNr zVZ-7Zqk0X9q_CfjAW0{JI#W_nDU%VzJHbfknR{(yHy*a+Dpn&(cFw#YR2||dwQv`SC#$!MM?k*W|cWffpOr9OcB;rb--AV9mOiHtGUlBm1 zycL)^6_BV{ema5)cxBh2X0r@;#FQLSI431IT50=+n^Wd z)RSt@t0nVe=^4A`9&+*ogJf?CfQ0daeAWDmZ5@FjU)5?_dm=^xq%e&-OP3Gh4=T$y z5AX|&vI&+xiG|Zq)qU`7tqSr?8Gy*fF6BT)S>7v6R}kbtkXS-StzzjXSY)vf*FWtI zIKumQwpWT!sv~k>+$15+T)X`=5^Nq5`ONqGAcf6VnQOJ{u+>EbRLAzN_Gd zC#&Y7=d*tQ!5E8iZdR(Ft`7zSdKOy&Dk}%I9MP5H51&;&1(f)} z-IRs9DHPCC1a2dNZ0391Ep>IV9+14%Ft&iZS#WM8kKE0RueL=y(GuA3H_HM;z+y&1 z2v&p}Ak@N>vh{r2JwGI`L72#<``Lj1;L3l$|IhUSCLrYXztg|^pI;Zk=>;4>{*gFc zNlFWjie3&g1WNm> z8K}i5z%2Au!Zf|VH<|?sG+~g z%NsLHj~8VULwxfZ*yGpg4Ih!LX+Gwi!YL^V1$a|A?+ofEi?#r$h62a|aTs2-53P_4 zMza24kzFD!xP+VkeYsOwq7a#3j<^vg+%*;DZE^So7QFs)VL!27H?YWSeIS~?+1w)h z65ELe5*$5^Zl`{KH$nY)#>Y?5NNVkmOVR-t-r^HUpd77$n!;&XU_XAcE`{KRY+o*& zUa~HUig`ACW5UjE$p`$!*d4W8aErPsVapKM(a6A4Bpdq4h9A>>37+C>EaFBxit-*L zMi#TL2}ccOwix1I6~BP?v}-^Y?F2=U+<>sZ8=LjJ>TJS@p~FF+;E`Wj%6$fYA|@f_ zU{19eVA(n78+c$?&C*xt&qn`Ngvfu1Mn|@`BnAAK85|>v!Z!lMCm`{e68`w68_2_2 zj4OW7xVy?^Pgf#CTJ8_-N*GGq4UqE^pfKR+_UkP!S2&6C*6Axi_ z?}es+$J}mvE52ZQI7`RvmVe4qM5(3*VL4nWVtV)h4Oxi*Y%dwhlS}ZFW09wvgR|k> zFnJj=6c$XuPLs16#N#~tGQMAJ2 zuYDbtK=qqsv+!T-IO{o~;o0+PwqP{qh=q)0!Dw7XlGE5{cj1@3@VB0I@zHgn%I9H2 zJ&){bvQe%1E!>x|to+0{l)+47Seo2&7_a{nhDuP_?5pbQ>S_U0aT}u{)ulTL>YFQ* zUxeGvgg))!tmlR9##T_?L}EtP&fl%)_89@l+*68A_MBM6EA-rj)z3jt{J_W(VI zoxf1L=Dtis7XX50uIU&;r=b9h1D)k5y}yD=%qRra7RqpE-n=#thFF^!yWZe_K$jN# zPghNOjO1(1Uj`&C79~cXhymV{2I_(T`?Z33^^t&Va)x{5U|+~FjV)!WGsjkBA3m>f z0df8^ka(C#?G6ebVEhNIVJ+cdVf?_{M~LSiiU1%T6r%;eU`LYu>Ut4A`?BERnCRum z1jaH5>iXj#@#bCq_!1tCJd&2+#b>L3JVEx_!oKDU>U7`;t|7nMo&{dz)6=7Ei-D}b zCT)gK(}gLv53^+P#==qnM`1_(j7s57OTq`G0~*kJlqK-;Tsmo~%Ssn8VLC$O&Z zB4k}jzp7{!y*;$^Y=1sYG9AoO=70v=`shp3U}JEn2Oidsrdz@|rdnGj5bb3)k(*4F zHFZXR!{^h2!R&I@*4Cj79^7y-RT#kMCclNPy8S%ZlLaf76r6@EoJX=cEn-sG2=ZZB zk-fcYmc(;FL{JLO%FY&m4*v<5Wyq@GIN_de)oK??%=DQ11#^t0ch|_Frq|bpE^kOm zb&IKigBE7L*c~X{>6#A)Sf!HcTa`E5BY{^_;&nw(=~Mcwtf7%~C|Wv$gHGsOg)m;= zaq|W7oS`O$a zU_-xBJFq%(*t_5-5f|b{ygQ8cG1u${Pu$!KndUpuyX)8RMFQZc>El*NTVIbO*YB~N z2%3b|^8b!ub}~^CZW#ch?6~JsrGCKAUo=v#cj}j8#5C^xaV)6vBFK8wP96nQzEziA z?5_-a&tv07F)+D8H%t)cOqUC;#XrFQlDNK`YIBK0f znaTuy2$;$S8+$rS#{ciq$o8XM~i7=!Cg=eA;uAXA*%&Vuq4lsFBPXA>Mwq3?ATpsp{cQ(c#$WZtKG zcBn&l1-RK$Q8N)HuUCAY zr@1N|8+@wAU|q7p{zwdn-kMJYF3EuUe@}b!oJ?2hn*U1cZSn*lf$^4vLD3ZSfe2xsZoEW-y-U$$@+Mps!9Kr`iQJD-5h=w)Jo03 z5biJuu-i0woiS49I(9F;M#F5BM=5I=1qDiO_6I31KG>|TjRtvF^ zYTN$sK&z-g2NgwsiNWnAk5s4Tmu{LVP2h^)kaF@%D?fg;h0csjU<|1gSGT*W4+kh2 z8ylzX1)f8Fbnzi5@zDall{9^~0>UVY${)$f&0=tAjo9_pIq}Edz@@c*H(q|xVJAaH zI@{7a^L6TnU_#3aW;e|Q-Xr}0i?RU6yvgf@!dc?s&$^i>=#Wb{+7m7#Q&|$sVjZ>@ z*3rU~PnHvKBfm%ex8wA`0XQ+&u%@{GpJkng$*;ERp zwdYQQOYq0U!}(5;*z~&Bk&ODu+2M3FKn`N+gs2Pj{%%TJkU};`AdgIddz}JbBm#M4 zZ)`8kig{|Xk`7c!@lmeLiW6!S*4EMhQ?w19ulN_nw2!Fyw0wOUXQ%1Z523&vQzaz3 z4lT7R)klu)Fj>sDlfijRV&7}NvX~9~?ZLKzyOzx`Y1<-0JoNsxAz66T`Hn(!c`@qr zAFk${G(6F^!YJ3@uhAiLS1BnUgCjYD9DcF>(~D7JMALbwY)`z!;mR6Qiyku^V&%Lw*hr@O=ln+ z!hxnKEla~xu*IV7Ff3jHV6MeOb*?c3`=32*Hc8-2h7vplq6? z)NBcsV4*4kH#*6`h>%uvvML{SbI8BU`Bl@|9k}G|5(a#iXOkW|y)DC7S4O9Zq<2H- znz#fzNf`?5g6uhyuOig@ z{ikPC=`$?7iSdN&GWpxe_KcB6N6@R?@r9Pa2Pw-__}afiGej>ZYWHD7=z|ZH2Vv9u zW31%1bP#=s^3J!+FJ`QnDX8DsC=3qYpLx;OoyZMn5)q88Xd5*(+Q??RsrKC17^M(J z9}2>hUAU0vNQ$4VS4J7A^>ZSx$31SkTn7bN>u(Fp6sOzPg7_Gu*8dFq(iM!|H-t`? zrOsnXK3NRhOEKgV5YU=>K8oF$;q;wno*By>Aoy3&;kIOONou!<$;%PM(m=$O&hfoJ z*ZJf37Vv}r_GgAzh5|NwPYl&Gc_hVP9@3bnv01()l(06>FN?ds&%@Q2Xfb|oJ+4jR zJ6r+!b36}gNu$MgLiS$GRBqTMm}|N(#A?O(Jc51x^x_%qReTtm^y&>y0?+%;-7>n5 z`_*s5J~zAB&S_b-dXKc5`TZXgun?ch&sRYK$(He(Bl%10YqQLFUQQyzRrzeEc&#rE z;obGu+L@P09Ne_OVzqgCON_i+41)FteT*j>*mnS?V!d`lYmro>fPi>NIS-0m4@uPT z`lsNf+Epaa6qhxI9ZtDxNLB!NkPK1@adB}Ao=#jMNXF$^JXYwog`S^lP#4@N3=Maj z*^_`5_XsN@9j6x!FRpI)>r|`{3-aQ~EQvXlh>H?t?ZYfJBsehs@jtTI5}tlpsBden z0;SQQkKw#dZ{p!I{+U&X8IWAXY&EdcV~jm$IsW`At<|D<(3?`@32D{;WaEstkhJQ5 zl5`#98>kq^O9^`u|yN=%-ioj;HMm1 z4I5r{tBnadcZO^M0gAxW_5%xC&}!(LcP^X6J#@05z-6a!bIpshm6lNL$^hGpE8j)| z*+>-|{AMY>QJEKU(Y>CxlW6xfCP4|2S!*liDjr1knd8xCK?uSq#sjIv-lbfy7*D^- zvu~RwUmiz}`3I_RDRnK5>!6AI-AL@6yAM3tb6A>~kdYzngo8CW#nP?pc-raTh z&NH7`B<4RufLy7O2bQ7!Mg6y*KF6fF;XNX8YVu1dcMp<{24m0}k#{CaJS1yzPIT$^ z25{Y-k?;{lNZfC)sHi{+zc1^zJNoHvZCP8jN*}S=q?l{Qvjt5uL**K>@O)DEvMT@p zvVPTm{F&HRlge0S9eGc)t1UnDv?!c@ymYD1qFAmQsKPA>-gVP7BzQI+o{x~e10Y*g z)m2bb%tqk#Up1wJY*!?rQ}`*HIIk_!3?*2a=EL9q$1MFd?LO2H`BUL;U(xVg6>FB! zJ>sm$hC2~ZhWo`>89gRcIom0Ze)#RC4#o?L$+a+=2b7yj3AsP6++Aa;Z-Xz31`zV? z!P~cQ?JolDMi6E=a5M?O@J-==@hsx^)y|BLiswCGR$Gv2>5q`-2ndHjD0CNV9`DoZ z$iET%^7ddz_KBOO{XS%!xS7|st8!ed2G_3%nI2qOotCniGh2efsP<)FP+7YhMO7BtH3xZkEOz`y;heN58siWQG{ zjXEUb$$-T-d$=S3hJ*_)auDldd&*1(*G|CCF0k&*qp}%vAjuL43_{g>&>g3P5=3Bf z`dBZlW@()UBW%?weE2xe)B3=4=+QsQm~?jCnAFsWPzv@e<#@J6?y7IbYfK;IU|SsQ z?fK2x@J>Mt#9kJN*^1EW%J}E^cX&O|dc!I_=V*rX|5*c;1w|J+m^rn@0T+xI$s{j6 z2^VUSNfg7c42P2_$j0@q?oAb?0EvQFk0S`zT0jPb^!jza&D%z>%SH+jnzrhyDv|-!X*@;O=$gyGJ8vP+q&@F9%)Ow5Hp%sV4CnB{tSva^^&B{X|dY!@~ zle@_WL;h}VTe|W8H+1;d7P1Y zT>x}S_5`{NnpU7uYDjL29_RMPy!wXX`(b}yOmJ>@n;Ug&KxG`( za;CI|i;~RaD`5FSKxF39re7mh`Vs%eFx+o9=y=<7gC*ri8EXaTibc#lp z&BJ%9iXzN4OTT?I27@64Z(7fv`8Pbc5X6}GuRRqS&}WUzjMHG)ccZN)i=(kcQoP9H~Sw{Y6Pn+ zc$fP)uff6wTC!X~dS)T0J*g4KTm6^3_kDvSCi1Mnt4O}AJn{VhQDDpST%;MQDm3i` zqc8!7t$i7uYY+uw>a(2uk8ni_2H9922*Da{_GZc+Y$q&)^EKiL=thkd=@j~bm{g`& zd)U951D;YsnRo3m!b)fk4K03*B-(v4Feuh_2Lh=D{ z|J$KoY_a3TP=PP-;+Q2Q9!)*h@lENEI)%rFU;r?tMfT+a6k!yTZa!K#e8yvY#p=J{ zRvH@xhFIdpkqRKQG!OvL22E8FIcVlSvMNCWfbrE9lkYD^KOigyraUoHBcKnkVsb&C z1D5Fs%e?*vMoSVH)mY0!qa^lT2u8dq2<^{+N1NT3){&b|bdmUsOK$?kvA+I2g7$i~ z1dB#H!J@hKKD0q6I-~b0cb@L&-5+wz*8spS2hYXe$qGU`cemstOUv6=GP1bP(EEAgSHryd~iPK?lv zCuSrLCoWb{2mNeZnTN2Q?EfQdpNSX}`O1ZCuR_h&GIRK$IOTWo@hrM=$;lj0@5_=8 z-{OwkQn6yb=R?59$HmnOz~GF{_$TY1_m9chB_)kbd5=?JkNZTEEu-h|2_A7>{P5nS zD>8)dRa@#Xc=8>|+f)U(8xznKI(3Nlef3F z=WLHaK`M$GUYeQ`#ANvKtv6$RFi1>hNlSv_!_{q}Ep!Z`QgdIEDYXtZ=>u2B4|0r8 zo<3DhY-?{<&a(ll*jgs&$6XkTHxuYmsPAzESy%^vH;dfuNkVh@-Ox$rnm%yJiuvOe z9HEUz?G{^;uWP;js=Y+!6Sc)_NOCp_Yx}zOvtN5~Yoid~Q*hQ&-eZ=Vn*QH< zh2*qLxzI`57RRc(P~2Xn1jcAkPc z+X)gXfc0G{O6MvygAm<|ykPcag>8er&rx=?WSmjmpU=N@s_F z<5EH{7~>=nd^M&yOoM5#Zpk3#-sab)@Mm|SAqCP?|&*E z7RVA)GOMlI>2+x1#VS+4jS9GJjjjP7%ra4nK^VtLy*FRwi2>k%Jy*O{C zr7W-^1Nywk-xbP4IkM(?LNPCSdX2|QM@_rTlcMz*`>(@xhyA*!OS5O{KN{gZ- zBn;!_10p#on12Sn;6?7Zh4?lxMv%p!s-R?P_#K=Kg-T`qnd=;?Qk`Lbv>B@RCl4#( z`+T>MFgKl{3<_wPq2T6qur0H#L<(*x-ue!AnPjQo|E-%0I+^_%bOm-mj*}A@B3}lZ z8VD)~kn1Ros^6y=pRLJ4_CFstSLogM|916<=(63FwbX~V?~|7^BMDRLRrAl68Q6^h&VlRZ9<}l4_(5x-%xtSZifS#R)NBv8NT(&BC z8zE$~ACRcLAQ`O!HFS2+3Lt@LkJaEBc;gNVgUvNh7UE)Kd>D`%*!%%41-?Flf$_ZI zXZYMBlSmvRYtd?fWIap<#G;8Q{3coL%WWW}$av*5r*_^JzWZ)2#~jL_t7`eVT-)k{ zQa?@f2}qqF6N))NSZvQA4ycX&7)YgoWVI&nUgzVR58QVc#C z|ET&SfU9drLEPZQg5-639>9jMYE7m6(c9Yw_+~%oFi+l9La+Ew{AcB(Q3*9!Lse4l z2RtaxJuP|(H=Ux-_j6SS%|>*KbhO43rgsbQn=I(v0Z8x6OY@EQVTHi#lU&M}GI_Z$ z+>W1jn`Y%YWpqV`s+u}DFjLvV%z8{_S!UHF3B1W^K8h51n;drwu3=e$P;nce`#s3AWL#)C*E9|K)Ge=#_VIwrKaHo=bMq`TGhI7HE=hA!~?9Pv;X#h>P=sTxE8rhmWMp^iX$5ZfwQcovAaU2F-hs1B2u;gOf$ zfdv}e^)}o~^XK9%DALQP&hvDdRX!E|E$iXFqfP%~`l|i&-)usy`-L`kHa~&AOLcW; zzg}7j8zw?0EwM%A$a^Ws-Rnymy-#txETn@m78j5(ZN-5J)ubRIJ6QE~$Uo18rRZUy zVHIfXx;)7G7 z0cLchFB9ZPG;{B0fr3m=RUdbEOLz9Gxh8f=xyIktZ4A8EjEJ3co!cV|oms@V#O99m zeLv%XzCj3duIL*omA{<)Y^wL8FQk0n=fORz*5n~Bp^fEgasN+K`XSK6uf*WF5Ua@e zZ`djuRmEJa-T;{>h>w^7ntY7)bSaCkN z$kTa!JmyMXj*FZ%OSF{&Bz7r+)y3TRF<$e9d|R9Td~>e{>U?WcBud|CUX9kHjR3as zP{|uddFdILEzklQ0=aZ;dzTT<8DBH2)72MZTk!LQ&Z@QcluKZPFIvji?RUq_D8sMC zDA1ZCgA}~#R5I>fX7PoSzV((&KhJMmB4NFBN}-(LVcWV|teG|LD%A-} zDYMmFGIH+*YIb6G30Q%8+fCuUERFxOoBY^3Gl0XqQwXAZr1%FW%#A&I)L-^Cw8s#Df+N>pDnwzHVk zB8v$+tFDH3-jopRJkvSDO*v3ki`;$OZd|(^_eIbqIFXyB+~(IEpu_L^trB%aUyp{I zjib2vH;e{^C@2B@huX8XQatmz)8c0EB!1^y|ukL!N z=UhgVtR{Y?W?_y7&KR3JFeZhgai2NxF!24xhFrCG+-a2ji{Hk_+dA2nBWEF&)~7P-9d*TM|Iz$$#F@FSHmCURR8TyIgnxggtNAeGyQ=TUk2j!Y)I&|HyN1?M`n@tDn^4c4 zb+0-=EDm)O{gPZuqF(VNDl3 zkN13&QL`vDI99BoTBL-+8=WP<6E$+d~*XZ;Ue#OvgI_D=ds&rUHQZ zhX~n;|AK@e44EgkdnZRPN=CM|JsyI<*FdQ(cg!lsWYBs7MZ7FP z2?~H)00h;9htxZw^#%mAZ#Vcdw#_yulLR-yyBEy{H~X@_okb5A)r}F*Xgf2JXT?YS zA^7D?K^oo}8ff9XKE||5>Ok&{U+|cn z7vW~Z*&BN42Dkki3<0ZamQ=^%(xZ=CLx4rW7W}XK`bW;cRNuFE*mAN;6gxVxJAcEJbFl&!7 z%VxXRn)|B@{OynYsm`YJI;B5)z#Z;)QsVY_kW*%`xhn0yz}*j1x!V*155q|`Bs_?s zeW2CgUCFTi>&I*IR49jYX_lMc18UFt5#P3lt3m&uIL^_)u#@h5m!Nf4PavhRT6$J_C0q?G_^zF1d)^T-zmW;(G9o zwF~6u8jtJMjby4i?uixXWTFRMq@%mk~E@jUq;$a#!&X;4a z#|L-!)sdPQe`$Hm(L!+Xnc1XpEL{?+`>D8|EVkK}1aO3b`z`Y_7s`k$z>#gss$v!P zQb@RAwsD9cqff@JQoTQ+Qg?F`1NAVrvsMkuCqn`E?;oe<4^?^J@TQv5=O+O&*?snQ z#n+3*tr5dbeOc|-?wG+exq#J+ID6i-(mPByWXB2` z#WEiW1dhX~sBM6vdS+{0jH(+ZkBoZyd&KFrtO%@tI1SI_a)_nZ%f`RY%F-%eZ=@l= zD#RkUiQE&K{w`g!Y|%1p4dDd^(-i7l2<5`CbJ!?NZ>`?|8>v0;n}0L$=az>nMf}>m zL}RTGk`3IeMeTo|4A0hnz7i=o>=UFP%fAsE#So!=XdOuVEN4|e6ZfSCVdD>#5YwGK ze*BQWP>7UGCqFyd69F}?xJpvJ%Ot9Y-GwTG-hXL%S(Yc|3+Sd=3Ow4ZsMEV@07;)M zKbEBF=FGzF*Uu@oCMZL$B|;R*;kONBusN9A7xRNxJMRiiwLd@d*wNB@YRpdSTDdSx zM2(j7=?D*vBa_j))wkXjFrBXOFTFXv@=@NcjreR;^W&$RjBIQ7SVa76T?+|t+TyGK zx8gYdq2a(V0wqDWy}f+ZcLAPM=YvZEPp5&)m&^V_{;}DtmTAXBufK~j^EqsO%(qT) za`Qa3^`uTkoUdxS{LwSu)T`6n9&mWt;198(zn$asOjfp=|Dn}pq$g&3e|6WJqMmrw zn6jz=n$fajPG|95iGn}AV+AsH)BG@rIAqmC;un$d1S7gyZ>Ptr&#tdH*1R8NuFO{l z9kjh*3?oijMP2?Y4~T{sA#okLfG?8Zvz*6B`PB8&t>Ig8n zpZe<6jj#ocs}_s(Ha1Zy!NZ-?Z&Ge&Tb^52Z(A6CPBa!7i@Jwx_B{cFR+R{2!c^O` zmRsAdnozpmfiO{NY|{~NzQHoCwv@YONHT%2SU?`ur{(`5>%GIVeE&b-2)U7UXQZ`#9y+qZu^xY5?RFFXUC#bmUb?;yu@|izF%J} zmoeLTJrlj@rBO5aC(-J@$&shH&cmYHbsv0cP$9>`a1VbEB$~vhI;k>t=@T3h-=8+! z^NRE^iJ(Gg335peLL3|_D|i>ZG!&6;^(-=o6}}jMt3?K@jc-*WMHIV?INjzKcxSFR z9Xs@YD>aR%yNy@>p+VCHHb6kBNaeicV+sHBhrS;lzV54ZOz|YD)Acb~r@>#KF9miM zKo!Y(8h&HKxZho7@!;|!48m`XBt*Cf*opc&12?z&Q5-U8J?&IhJ5aE!I}i8BFK#cw zw`^kBl4;%I@Aq!GW|q-~;9yN;9{E2N%!LrEZ zqn|s3eJNrT77vB`M?mbuuAmB9js5TNO(Gy*F8_gx^BFXrO^pf_Ttk9SvF+xrKtH4z zlEl1AH(N50=j|}7ao^b1phTf_9)0g5K?}@Vv(2klV5*@8o(x_p;f}MRNR|IHLtT^4 z6=g@GL!QsqF45tC?5p??s$MhIsnH1g)HQb6Xdq$%X(jCQ51V#{n-AVIT)&P6jWL7| znlsk^wB5p7vh1CINkr0bg^q?};EyD{nh4O}Jx(qkUK^^LZNiI6E_Zyq_9f=zl(P1h zmX3t+hWS*%>a`_(tLQ~8Q#E<%r{jo{S*;RWI4?)K5LcLnejQ#5f|b`M)p~{cOXC%J zU&yHTQp5kkgpvW@=t#vG>lcU{WI5(Fa}FHTFy_6}(=M}j*tPe)9BSGWw}e}OFStIb z*rETBq+*Y7=XMV7S{T0Z%_6(>I~(h_Umd57?;6m5{#Z-?lyv^H8P>sNlJIDWNCZ8^ zzeaRbgch5Tym14eOjJMg((?NPPp;aWm2Edu(;1c@a~8vPY|LF9u=A?1#^z@(kw2Nz zbo+CqnSs1A;ybrOlwC^#x4GxD(6S9L^M1+97QdfvgVtbnZoBv%T)lfYij%-@1mIeh zaP2(--&(pJfz@5j^WSJOejyFJsmZcMMq(0w&5K@qhCcHzSZMVtDb6n-90u{S^v>M< zzL!+q*4HLTp~&Mhm9RJUwZJ}e`;9G;6q+Bw=SH6CEZY~dGTU*4hCBbPH^N>^-289d zHC1o0-d52s$)UzVyWvEUk8-3MVM`NU3v;?N{5d2_!fN6((ObbQRj~m)eh((jagLO| z9A0@{d@NBA*-2*QAaLjXSXwh~1E3;^b$%dZY~kr8F%8d18G!QshS96a@EpSWMnKvZ zy$YbE4RB?uJ&euYw5YKJY1ZIVNcs_W3oi5~Zc70;^zNe$vVzvZZR=ZA>J{|=cQ8v_ zr7rLL-%1PL#u;etB)F?z@Oqy+o=e&%TQx+kV=DYA%ccCqVYX>1QM4DJ{oEt zSvd`eb5FOg_{hnOy9~=E3i=&?lJc)!CVE}vRlPF$whc{raEC<)oaRH+QmEg$0Mt_n zNP#Dhb^G}MQLjRG7B2xgySA_G*s&Tu5e&~yfVC-+BaKPOG|RWDZ~)m|eTb~OI$?W@ zVd5^h*U5oK_8=&ARXWa4H!YlN$PXZXyyQ`FN%sAd0)H&q21;DhoZJ}+0h+=n9=*3h zYX!@C4>6No?KMZ|Jm#ucxQYAwIz6f9NQ2P-i@N`L?qB+-vhfymIgAPaepF*r&T~^C zx0&SZO8Jr%wCa>ny{p6Ua>?(NromjoJWpAP@ciwhx5pnpV>73ZQtB3U^Fw_DzzU8n z*K&c?^NX}60^a}A0ti-uqlWwHTW2fl}`b041Pq>)zJ z4q^fkhv}l%VzHJK09_jk$geCqh$90O!Hb zO8=W1fdGXv2lALU(eThvHXD()j?N9H$XhPCm3LH#ngXg=;@KpoqPN-G^*Rnb7vAVh z5z|r$9d(!GJlXjD^x_>61GjY^>AfiKR~xHBiWahW(rBk8qE1(FI0QBrt_(!_Q3p3t zYJ^o8w0|iF$J3a=40E0=Gk@qj6TxBgX>k%pjivZ?l~M?^-ybPLQ93v{a3d`!kldFe z2<@0G1LnU=%YE4!`CWb5tfzCeo#^z-HctuZ*IJd7{zUv#GKs3B>MNl!bRl11N~4js zo2I>@`3#;J*LI$B9g1p({3*_PrrlRxq?I?v%p{i)2U7Od zo}jNk?tAQgwC_)`Ia5R=81bvu!L0dM>DoI?+S(WRWHje9zsp`<%QHQqc@?SlwKA>f zt{A3gxJ&}qonU|(A_!j!EZGldm{*?y*I+gff*y@#O&Hc2X}HU$KghvMH~x*6MYVDL z(HywS^>abMrX@7k%t zcSLnw$Ya-Hvk6!wnIQD!tN~~38592SpQYzB&c6KKGX|#zbfLzZxf^+3#l{*&?&-4a z*XEjEHC|}zu3Ef!)UINjKgobMi0VmB(cDjCrP=U}bp0u~smg$BD}h7io7b-E00IyE z0Gi^)je!eFd2fC{H@Zx#QUnw zN<)nA*-}T&pc{F*vTSh}ky8{C@(kC&VXxhY!$Nud<&}%aFXazXv2La_!upwB{FVS5 zII@1}3b?p9jVf~m(DhB zCm(+S;QLLg8A8h0W69Xy#_o>R^%y@C(n*pb9m6K&4Un!0K85cg5a^vf#y&tg9L(2Z zIP@05E>3g6&C_V;G{k(WJ!E)hU*)jJ!o0z{?=BAYLRFiUgeWQQ-eo#+k2_#=3L~m4 z%aXBIF<1e1Z6BM;)@HFxz6s+xAyQQzk`$rB$P1+h1^Pet^d@lMlt>jGL z`zS*vN!L-akPlK>CA!piz91hQ{c`>e4X`*hSU4ClzJbbxWBn_BT2f6#+Pfco09U*8 z_0#ECx9K+^Lq3AZmFINuZo$_+ZNro~g3k=(824EPN1lnU{1zCI;! zi)A=&(<*E#n{L6v^i~YX`)S>q=nvTlpyvsnEWEa%J^SobA?z=mROJd^&(S=87KKA)fSS6L(JB_fykQZ(g!ymr}z1xe!ISNNK zl)+P*$vqQ}^iaA8c-2mK1)Sny4F#QMR+-A1)>E+i%H=%ksTiqqdNA%0t5?Kfa$EJ$ zypS2g_#RC&DtV6}DjUzFFk0GZIihB7COek2D_mPaoW|3=Zy!?aS@`%!IP{B33FIClXfiPR|C9QGZ~69n)XHyh8Kg<cXJ&uNe(kWq z)y}Um#?ICWUdl}SA5J@LK7U1%ZKN7?gG7b%DSnlUjggIO{(wYz=aZ@oEX)X*j!L2B z<+);w=#-Re0`FjOLg}(t=S%ow`e<*>s};QmmeY8i5*mPPf|(Z8-d;Z+10zP---N%d z6x@Q|+?@gAK)O`g5LbNHic5A=4bw@Gi5OmYZ1Ozyn&u&P8Bez3_<5G%rP%08$0ypY zI%Q!hOG~_ZUAEU;3Qz%dMpreeM(?^@1m~ncP+9KhZkh;@=2aVG)%_OCzw@43#N>%# z)j>9!`m~eS-a8k?`wt4>yPjV6=;pX<+ra+NNj2qJ{u@o5-{^~& z8b0;kt8+3_zZCjs%Q$OtW>^0y0qfTtFl4n?ZT*?^PP{pg=@ZFsVVtQ_^Yh>~8ex;> zO^ythnICbPHeCgCocI-L{(HFMmM&^kmO0P~iAT`mFYPSzZUHJ5EJ!JO#d!3~h^);X zjF)4>J?-~oLi)j9^0)8V;YZP}(XVF?@w#u{#2LPXyG13p&oPhU#oSrp{5*edQ8lDAvPp*sK26*OiW#67!bf6EFuxz#E#8^X-Zy$^zzDP7g2lK(qFH ztfj?Ijos=uX;V6H8rJt#@%z7CPMP-^nwF4Im;E}RdRzd4paq|w?uvFM1&|tgJ-r-H z?a8#{VU!Z>`|&jU^pmvth$&Z%jULCJXnZRp#SB+f_FR*?OM_Z`MuPpGZnU%a34mm- zj}RcSvDd#AP9+;&SoFU@t=T9HaZjlS?^erW=qi8X&LIfFdWr@mVMb?X=WO2&0Sxfc zh|yS`X_f*(>&V1Jd`D3T7ua5pzSEO$pfxyib93hb^YuItZCHHh=RL*QonqM<1IJ~I zW9>G!65r$f*pIv71=eOys?b+z7TLmi5b5)Vqm@E!J*Ze4X3a$f zS8T4qxfwzDM@KjAVF7io1tyA{ka)0(jvhk_EP|-uRM~%(g&y(m_syplE!I5+g-xOL zI?`VUWQxwPU1##5u4HxJX9oKbgpZSQyJ9m{%;nccqq+5Ie^}dLX80&JK+qx%%l4`U z#=T|FD>h^XZ$n|qrA~WE?Vh!@^1cu`(RlonFOv(FPtTeD?%3zmv->7n4K8|0Of{P0 zYwwwjsZMSk|5&=DTIY(&gQA(EmE&a8pQ2RqzQS*`pm^5rog2f`jlBVtFK(=vdY$Th zDRzAwTwHE1fqQTzaA9EqQC1;t=G}kLR!Y(7&6s?U;|YWWFacnmiVeB&y?q3L@oya- zX}o;(DyXuu5}8cGz6jC5zA(SIN6Bbrg$bWZ(N**@^<{s}@Pv;>^Ittl4`x5o7m0hG z-LjGR7O5zZS}chXq4RFA;&ycoiNBL10~i4MgAoylMZwiFy|>!fAUG)pa$tfhOod-# z{j}8@fCzXn+I)t+N&5l%bNMzDtfSgN})3tYFZGs z*TKB5(#|suA_QT8?)ttvI<@`e5y+Z3i9?KyOgM)T?YD`AImH>bIt65w!R%XT-FLk# z_f*QuhP`q+!%{3BD|3bs^|n#m=5V_xjHdyG94PZkuHz6=%X&9EE@~DO~1g_1n{*Ybheyl!Oxi&CxP6n?)@qz zu3J16f)hVYR0Z(Z`n*3B6C03a{op!;S6U1Q*a$r07?f+(^n!$Yi|1|00r4_fATD+UYATt_eqtJ8Th;OF-s;kFYZ5 zew6)UG^4<5b%+;#WNl;f9qfMqUWEzikIeA&`Oe@H<#38C!D}JW?K<)s*G&Arc6~KA z9H0?5FBdnlVtvQy65Fg(GZTPCe;AIir*fXzNZ|LpsJacaP{>}YXi<;H<)mLQx4U9l zyffotinRF!)aQx!jvF4I4A8_M0a5_{*v`R#^GQ3ov-!MhS(;B)OI8}m(Yp?sC;a!N z`)=naPk!_g{v?WKbuOV4x9WE}_}*K)Ea&QQ7O-&k-b;Yc%9v&C{&%0pA-Sj6PdN7# zyD2M6ONn6s23^aibX_b>OJw(3;_m)Ylk`VWQly&xP+pPImg7MS?ISL0?d`3~Qpm6D zN>dUOZ^A=&{O_Ujqnmn;C>^goy?pqtBB=vz} zFM}uM=jR_NHIJ_43&(%Wb%8Ej7Y%#_O7SPW?WaLDUf>h63EE_y(_3G$u=ajD?5dPH zvag=a_ma?AzU8$a&N0NCJIgl1hG*5-^leQuLu_63*8@zd)i!9PeLQH)%Lp6&E zx36;>p9guH#!>O?G0ld5Bz$vv-eM&%#bc3TSDRz&SI_hdb+R-W=kU6)dxc-6M$nfr z1SJ`&9j4eXRs-HX`}30~+;_lvxR>(%YcMgc0(zdp%R;6Vp<{XLS<1-N@{{Y*(UNoc z0ypV>oR0$@haUTGLH12fX3;JQp2H>=F`ajhHKMjZ*1mN%%9{@4j!WAYO;*T4t@cg@ zQ0x)%-;+EJT+dq(UZ-AGoISgt_#z_L8%0a*d8LO^S2c%ar1f^~)=6a~7;Usc|DA3j zdr=V?kJuxlWFf5)B^V|1`)k5EjzhGSN*C|5c7{Ra#!;}L;j?ZMzNdEeqkG8$`P@k9 zm$;huPldmz*NL|!J*j<-3fjI*mn*{tM3(kTBB^R8TqGKI!t&l-5wvGii(m-%au{JC zE^(_>N>71n(#$3nL!;r3dQRkceW`Y!#- zi*E4Or)q`Ko>Ss$Ze=$L6=)3eoH4(Z`?eGwch>l(xUY|D^^_3&>FvxhnyXLw@O$R` zncD57y}50{tsbY&^pb`xJcLl_ehh{fuNG=4bgG>pP66Z{@Gl0j%)bEoj2k8`BCL{0 zm$YX-SKY3VLB$h~8=69JQ@ZzIv*4oFQ!nR>LTP8r*{x4rC#pEL${WS&YGIy%d&Hf^Z)4mnC z@hE@lyNXq9?HhIIt1fM_S!?_Uo=U}cO(&BArARreQO73kD?yDI$U#9Jl3K9-da)TcGIa<>c3oi2TCa46fh{d zNZv8at64bA!;NSGVg$||qb6QlkZbq-cXC6GI}YgYV^2$+5be)r<>@VJzVcGv8cCR3 z^C>vvdquiE?^JQg|02ui{L}}R7`-Q|RX(OV3;M1_zc2N4<{0bd(GNG_mCokcGS=i7 z%v(EP#ze}@cr0E6uC)Q4wrU>BS>)Zv<5mlVNsVx5O9|i!;%||ODP!(25ij?>q?H?< zHaQAue^N$)Qe?o@B>EzA>#rK7_pPM8Cp0gZu`u|!MgjfHotRwnkCrFW=U*$}oXbk_ zYpU~fv1_Jlv+aYq8#f(0375`B%i2%TI^VLNj}2>Y$4kpRl5DzBOO;0bhlud!pQ-?- zkimAvj=7$p;zv-0>8cf7`)!{D{c6LNbSldM#FsTm-w_<&iG8ov{B6}3L6%*p@NyT9 zUXYq}L^9K$h}v-}Fvjp11Wi;ah{Z0EV64#5Kdo*M(FReG_i3E;UxS{1lselaI{9V# zXRF~^;sPxLgPc*R;dFNZ8*T{C?Z*obTcZFy<6$j)mv!&k`^p;S8qV6c0&8l+ zui`_Z7BGi>%x~|sq&8f8N$unIYc8t6bV`Mc;wXYqQ0U_Bm$eXC%^rzDtJ919FHLJ=FC=}eFgK(r3IYk!b}P~`#x?Z^!hm#H*X z@c?5lU%9vfy=cmmpjTt%`H-8u;Ok!aCE%5P+26u|B$DiE8zQl(^CnD+e?MJ4!V?*N z;%$DN{52jH@Of{dH!kug*-njOo-()i9}JLdbK1iy_U?B zv?t1__MQ0)jO*6f3rGFofFtd{jCeTUcQ`jO>I&nT#nnRW2oX~6axw2Xlx+$hrq6d_ zme~Jl#iXkUlfkvkK*3aYG}A4S&kYaJGIIqK(M=5xLmo`~D4E?A;cs-1_~F3W{QU8H z79*%t49r`<$ZdS9LtW`&L{JbQ)Pshd^yGbLPw*=-3HY>*hE#eF4b{}1h*n$oQJuiR zxgCfNn&4aB@6crA=SS{YDm}JpaSj9==@aeJo|>TxN~jl1rs{64Off`>V{Y;Ye@EH! z;Rs5y?;&~<+(_Ftrr9{0b!V6!-5uwxGzIgLC$BNKVm z%;JNf5z8PcIlUcULQa<+N6kqpS-%|U7msj_l~Vc?t2C784}S~Q8vMJcP<%M^)>ko# zJJUNA+T-D5tjfd5NGb0&yxEe8RoQSm)6P*%%l1ZoIWvjPev+rt<1=rCl4r2V$Mg?V zyp3$zLFPrJv@9{N$sqYtWXKvaqlKft4i{X&_=W z#gq!dH6?~jxVnn?nMq42F`&~6uT7PBecfInznmI=D)HY>#UVeH`7pv8BrmB3D-xJc zOF7R$ck${CXDo0pvFqmk-Pn!0l<`73S0WT&>#$iz)4JdDbuYjuqF{irZ6MB1;*DPaCxjSZZ2v(SKg&+MQiJISw^ZQ46w|2wT=} zZ_6fo76g(D!jS&(mhT0>=>K% z{m*Ot%eDjQ7>H~D481-b8xExUnOJJBF_x?XQ8Gze5uJ#SgjV@!We z4KloepyfFSI2Y}HOG`^S)srg@H8LGH4daZkb_RmnO#@%={S@MnIgAMVp#tLwrqheJ zR8(UBil0h!rB5ifO(16!A@N+R=t;cUVu7{Ogq%?y|0RiheknLO(f_VMFKM5D;tE%{i05u_*u2%wdFQ<_HtIwLgaaR^$Fnb$NRaaEYl z9=@N-wGb#$zKH2**H&Kw&-rDILvu4ZVJe{}`x64iIyF*ha2`(eo3_+6B>_Ip)~H8Q zixUkbBtYlGf-MY2^ZpGOb9O{y7z{Xi7-H>#!KCTb1Rah&ox5M;d53)&UD59_ny0Sm_IVn}79o3#FT>%nj+~Ku? z;^cFe7E}^m)UJZkxrKw5!vqPhJpnuYM5%e8z%%_vkIF95O7T>Fx_+M-qmXnKy{F%I z^;iv4h~Df6@@=@_b$^tJyYWJ#-r(Q2!5}~fEM%#w!~(OUon>N|5iiGin>ApWZdMkL zwSS?M3npmgdOtZ2YKK%Lys~JjXKnVN^c6&{o+in4I-ywPI5%GRcr6r;s|OTd(wK_2 zZDNx^H6ChB)7q}ka{9TbobbZ*KKQ+oz=(JIU9c4yit+|d-{;SrrRE=KeR3AZ5wn~S z-`c;40nlMnMWK@9ed8A+tU~`JX)jo1Hj|K2BEK$QZql3;W2IH|B=^B2s~XT=Az_3v zf^MOTJo(^w1Zek@0J+WmVVkFZIS1uSV9ZUSUt$sg5K`l#tPF;WSj@7SpDJvFg7sV=kz@;mD9+O%dS>R%QM<`J5)6i2 zU_eB{Y;PX;xv^RIVIBrTGhKhhMk&I-1i4qjw{=j|nE&2K+&cVPc<03xFVmj#9;{wo z9I`ZuETyPUxUG1UMw`67c2>TInQnE<8^U}8E|87hhU@mEykr>HCpl5HAU@52UqMjN zE7v|QkwN_?#n*K3O7RP`+*6>sX20bFq&}T{nvUg1RslB3V$??ZNQr3_Kw`S<+l_EQ z2TLA!IuM{Aq9}`>!z|$5y?fHOtrg%huXuD9ggU9|kD939&uk$`Igw?leYNGRVWUEU zDn~*&>}*B23_cznFEA~h?tV3Jc0GBip$LpGk$AXp{^PuO;3odGzD1m2=SXM_>bX{g zaOGhCcjZhIAp45|Hgzmdz(3m=_YIYtVuoicLDFvk-hc1_bO@qE*UybWC5CiHZ{51} zpWHHz1PG3rgJ9|bsI&Z#26`4HX(7R%*jACejKXJ}Wrf@5TATxp3g!Z%S#C0u3`j<9it>F+?|A}C#rU^W zPGqTRp!vja2h3C2=dF1Q_bwHX_h!P5A_I1$M5~9K9=&|hTI3rw&0kcvBb|Go0$TW~3Pnd(^XtWRCBh%|Co zA>oZ>Zpb>?Z~hYjBE`nj;4LYEFy3KA6bE;UBu2$@>+z>#=!(vRb&|f6?FePG-?+fs zGAE*=dTQDyfd{103yXn7jR8)wa`H%6=NJEh{ftvZ3!1v37`Pk zXISF?b-um*Sw?zSwQ~>UweyXy@~(InPi1sn;7Y)YgHnBSH;(St@DWN zI&cl4N36$erYI3&dgrS66JiMbdN+*p^MXK8a&B1|S(LYFpC}I5rG?KaVeZo&N;pHn z$O@;CqJE>VhV0Z>D(uvMe3(O2;vo{>`HuLu(|aiCKRd+zcSSlXB0;D_#|5;Q=-OY2 zylI{=&}aB&qX=(!}2U44q zau#?^u3Bo6tle>Je1?rr{?XqQYRaMc%Krq@k*KDDKGjpgTXh2A?${0 zc#CL7zSjtT`{m!?&K2z{=7-<**%?$Cirt$xxD6duy$k2=L%qT)2wR@3P9&y;`I*)% z=kFui4uM*%H>8wg{~nnPBw42o7An8lV8bIfdmle00LUnapAD^p8VkbsHn{uf8R%ex z_O87r?sZiYa!iaukn-`y?Y_9J%Ml@?5Hi1^pscK%IJm_R*?b`~Zm$Y2Yi2Z)!_=>b zl&qu?w^%5DC>6fT^#8ugI|_(kj+I8TxBg&|`%b<4Mkg>Aqrt~z4G3Maxm|V>m2Z*X zlxYd|#AQ%5A;rYtu&2K|d-QGda2I*IkNL}2(v`*NKfinZ@9hfyeY*;7`?uBL?b3+4-Zav50v9b- z@Z#L3i~j(_6^WqB{5<%wEj>w^785hN+*fSKCH-Sfn#V5lSzv*@@Dc63H(p}}mYR#! z;W4oQ5g90T*KfMag-U$s7l#y0_ZiqYhzcs{=2wmW)r0z9u++RvU+X%ikqKs)>=eCa z#8}B-Bx!nI#|&Z$!tEOhoAq*!R+qHc=D-GuQpAZCk@dg>NDfDojCarnW5@}G5JIRm z%1VS0oFny{k=NO@QY4wLofcAYKl|V7{HuRtrIX^V|1}7z!1$L~pe!hVFirUPSqxW* zEfOwvoJsw86+2yMz%vO0+$}Hi&m^Tsl&?GhvkkmYhz*~4vKTN_h)X{pvB53J`ngP8 zo%|c)EB|6c4xgu|`DwDe1WD})#zT8)n^xjB?Qi4($WfH zQ0`fDT_`?}!G>$tQEJl~U{?}(uUH^o`+3M@jx>>T*NoOiaXQLC?RaO$H3_QPQ_ySt z&I;17@&FHe9Hg)!&S5LNa;{*~gJaozc_?QGKwIoV06|vBQjDM%lDZ)@iYU((jdH)< z(;I%fF#X!~$8TRUO$pDPbZ`NQE-5K_$#TC<*;4biWr$CpUmU8X^u4p|pfE8n3ZwAU zFu-o3@pq9>{#I(pB-8&El!-D>J%&O~Q&p7!#=5F9gJAMU1wu}~APDhF+?-79Cbi<% zI!7jn(&bX?{?xv__OkPJ$LsZWFs0`;UX#9iQ2CO1b;_-ya^vc2g^SHeN~XS5Gd`D3 zztjAg)v4%~>`Q`(qU;v~E^DP&uu1W_45ApA3(RI6G%CDnjlr@}!EXqbPeZ2WZ72+n)YUl2ofQo>UxibKc zwvs(CFff#H_eo&e>}mH1&MyjA7d0Dq5jrA6+Nc3J#<>Do0lA0Hp()FM=&o$QE6!BKeqV1OaB|cAix-D| z8`-d=uy6um$tUJcF3vO#PL)Z}(da&VRZJ#0ck}q8ON3wC?r%`$9s;t>CF1v!&iHBk zECK?$-Ex_X7##Nlc1QGvn~rH5hmYLulSzXYOCBh%YXRLWPW(2hK6T)P@sW@BMju2d3WWz(7MB5!yqq5SIwy>)cVG2Xv7tS1O>xIeYr z7;HlxPSxqjAWlX}H(Z$GcuY;YW4X-r)IO3cRUO@TlV|{Ot{u=YXRVc!i3Q@@BX{6q^38cF&ym2RbFS=4Ge}R33l&Dm+!h}f6@e@~7hua;s0|RQv<1n4 z9!XO0F0>%^Gv~3sJHSpH9qLDb>|s5N-DMoTbvS|#{&xibE-(>@2=PJ>#?oi)hO$w8 zudhFcR#pCw?pLMd%*tU5$?SHZ!LzfJ6{QWej9s3xn<|b3AYz`)G*n!uhCZ%<@7dD= z?VL~v{IqAdAJb7I#;{!f@wDO0!_7-1Br-gWJEVG0>l1U`c*!3wQ_DOw%qAoh4+aRC zSn*sYQlPX2*2LgWxQW|RO2NZyOM-h-Nje_cQ{#kc&Or82IGD`;4(3Xd)7Q%P{VMlu z7`MOR=#K_TbUu?Bm(5;%Ygqjb+%iKpE-4pThUtBL9WJ#loTpX%RzWp;dxqxTN>mGj@e5+I8N&kr$Q(IJO1 zKoULrpkAF5JcdvV|}4=Vbd;TwDjyv**uUfO;2*)1eXPV9G2}dZS?co8T%A z;kPmL@aiqE$p$uduh#;tp6dm6f9zRk@OI*cOXKVadIaWdH;=s5Yo8;2G+Vp7R(WRU zF^Gvn&JlR|2l(gu`4wT^J1)Z-ZhDaONhqH^Ib_o2UnsO13@ZGq&vTgR|3J&Ay8EEA ziZhAzY-0|JsyyhrY1TdLIbU7&OzE|U7f9<oZ77rN z4~cRlGgIOx?&Yur9K`NtJ3*(U`yP7x8SytMf^C$`)^pv>QH!;r2#Qf5s6 z&@M6$Htmleg9`Sx$NIRMDRSI8(SGKRPYDJviKA2fdXeKM7T??($lfLYACb*j z)1UI;vh}haQ&3VuOla+(T|30d%#sD0_D#fn{VK@nN4|`WJ){$2;Y(gfhv3qoQFYSP z>uJ`^g-Aqe|2aG5qOoxoWvyVQWJ%m(`bxh|`9&R2E2ep%YWA&3h0CaNHtcl*61D#B z7$ve}bCE`{V|XOdr(L9~$Fdd&Vr<9h1&k!MF6kF)zi;I4m)p1L4NKC|`9q6YT~bmq z^7n0i4SlssL<=wiLaxGaXI520>9WP32SI6J%J#g?kMpSQy5Kq3Ds-3*m8IpLych6G- znekd$EBkHy`E31}4Of8hoC(v27dGYZcgET(Nk~W(G}@@)vT=aR=2tKk;*Kf8;76l^ zea~!Sv7#ltKpK6sH6##6nY6_ni$wJ}v(Aq>bj!@^!Q3FY1`WfsE-nx-+pGu;rKd>` zJrJnJ@XMn){YB=g*#z43I};C22`gpyJ_Jk!pr2$t!>7;&+7x4+|9YTb8T{y#Pc&75 z=Wxd$F!QjVPu%0R4P(djqP!<}z5^wVK9o0`pkO_p#A>D`5*Ht@2yKTPs61K6Vb)0- zarMT~5I(6Kk#bGULGn2PEp5E%#J%37rbpj#o&^QH;v8eVK^Z7Ys0;j3Y#ba>$&kAc z9;V=zMlTAoV`30HDV~#xSAH2YRoRtZkj;GWvp@B{$foa2a%k+k$m9Dl;|XYq$Gv`i z3seg;0g=c0Jkfln-rdn^#vZlQYEQD;BsCCZ8JwDg2-fAm6&cg-Vp8jD)%6TNHH


M_(ro-e<%YlgAiM9m`x9$t3#P`Hs^ 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 MSyh=lX_Kq}2VBnDs{jB1 literal 0 HcmV?d00001 diff --git a/Myers Difference Algorithm/Images/EditGraph_k_move.png b/Myers Difference Algorithm/Images/EditGraph_k_move.png new file mode 100644 index 0000000000000000000000000000000000000000..a8ea45c291a02ce0686f7b247fffe3162914fdf1 GIT binary patch literal 206377 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≫obAIq&=+?zT1Vz zAmgQ9F%8qLtm$PYnMdcOW!aS{ZE`JTipu^rdb#QM=1GUVeUUQ+YLIu4M$jM9^NtT@sz267Ulb^e?v&U1(il2kvkdCKP3Qb*&<{4gx=WH_-j zfQzOw`cOW$Gc0cF%ZuYEMiHzJ^!|gL0lA9y!#+CA`#4ioyaq&aJME;#^4RO&+elK= z-2GqtF10%irR2UDTMB6ejjWGo+nYDBDt7)Gw0Ehg&8S@`++bw1r_!8uC;l&AI7ABh z8p&K@8%jvv>|DC#fOrV!3_H3M@DTgZwL6l*DwqigU?5*qrs1AumhlPz-MhQvWrNB0 zhQ`7zJ+dOJe*9?+bvwJ_LtrwW^>(PfSW+*KTQ=>$n@*OUi%p+?`Jm<=)(qJqH&t&u zbNtvCiMZlh{w5~wC8)AyI;z#H4^c72w`qv6zPc~YITt+iKqV3Pw#bNVu(BR6SseXC zZG}}s73C4xOB)o_YO%fBDVw^+_0FH@@0r(&KNyk1T3xToWpN*7HuGKP{yZvjiXj;M zMKQ0F$$s*L;~@UUl5wlh7+x!JAprlGE)pqh)@jD9wbOaX=s?lqAM?t z1$s{*5NzM1jHmuUoxe9pZ-d^?^tnDFyEx(;vXgy|ia4PEdYM0s^oAU5>VWDUw@S3> zBVUrF1H#J&wOJ224*Duia`m|m(ya(7BJE84 zR4U9}uUwd<>;y>NdkpZPg#)NI;Nk3Zt%De$@Tj(dUmBi%wI}%XM!#80EIg|+gE?;D9I(}xkA8t+*J-oO)2rDVRO*H?lA znv@$X;jPKZ$=ZS zqz9CKhPL{pf=jOm2R*_s&&77aSd|b6g>?7!5*PgX^$W$lP;OjqXCiu&BQsQmJQNZH z8flM;#je3;=PkiI>2~mLVEng*y3W$E8sxr4r-|m?;i&&jV_g0*Tyy*Ht9)&8e$1_N zxSB&&esjEeWxSWatehX5kRtKn;J1wE_I}*WRhGw6@-CYFq+^uUcJO>eRgc!E@ruxc z8S%v0ubwUx^Tp%GyFPW2zgq8D0#CLd#WD%)CY7M2g^T37TPe1B2Qhtd5h7LAR#qWL z;eCDT2Kj*Me*u$y%MC>&Qz4u-g=Wrz8#!fqZ}Zo;Cr|IlKDPEAbzW`Stm(q+WahN$7Az9TZXOwAiPHKVYCG;J8QhPd~K#S%3tD7{m8DBNF9lU$FVS z{bM5LB3jqFXWZ{o-B~lA@osrgJLgNKO4q9Mty#MX5i;_oA5Hy1 zlEpw-!OE)O4(=1&o{5PYs07m@O{#J?_RMM`E)5eA&bbrkli*^Hm@p{;!g>BIC9j9_ z+h3V#29AyG`~_bsmX9>6VbR7v_u0og@N{NvT(hUW>E&HFy5&w*?I?K*3oP?mj;3=Y zB=cqE=$f-!DI6b4aoZVx#eE_5jEQs<({iitHSyCJySt3Dmk9_H(Ab#hRDUMFoq5?M zu7z285gQaFd?`gD0!ek9`RUO>kx~G7|A@FaYPWr>K+4`2T6U+u--eO%J*ZlxPSJJ*MX#wrZdwcxG0(yM=SA#8<%#&DGEnvX=1_!)mm@nr)F1-^;u z>svGA*B(`;x%WI+m@0yZ)A}E?MM8);648r@%hQu51F9|$Cc$QXjGC=BQYQ- z%U;`=-$dMgcVKRm@tU8-*f#XO)PQ!Rdvgmg4_gs^U#ICtWFzsXEFU{wIF0#0QoVI= z`_eCCmEzre)Cg65>n0@fgnK+y7R_wk+FzX?cD;MIw^cV>03j~w{P~8~hYm>PzaPO} ztPXPCS45#uG$(ibVEl>(sPrx{%kig(JATndX|8BPrP`CLrD}Udy=5VygQQ~^6Rh(7 zvG0g{uz_v6g24`jb6O}~Ut}kYx`oK!6Mty;_cCBNC-r4hWu^Bjkk2fl9BAZt8uYo{$yz;wOMeim^~E#)=$4m-lj}Cs+oWR zfxTc>y4W5oDj!wT5LIFEU((zQg{$FVF&m&RqzYw}!4@92OrZjfj@!B|5Zp1rl&w6# z0->=-Y!FFM>M3+IO;$`W^$pim{0cmq1t|~lA3bpt`Ro0jv<9f8m);!B<9g=zS<~#r zzJOfCdSj$0=p(RlP$SYMS8o|ILPo1EgxIZ@tH#w~B^F6ZvtM7YS@)12p*i&FyH`FW zvPFQT$=&qIDZ2PIBGF8WFq|(&%cd{QBYf>LX1|nyl@B zU4G!h;wtr<9T&nTNzz27d_SA`1~#YM$KH9ppy1SDseh3#3xq->IhK&vT z7h!)N5}eT|&2e%~g^;s)pFU@wd&qVBecHr1Rw)7N(Rr%p-sMkry}Ko3HqU~_-#wbR z;Wz01tVmD@!52MgcqjcA=7~P%<37!ByxL@xNT$z%?4XOG2IsKK9T=zu_zxih(!j=R zpBVyvGxFh4s6ABt>Aqd!)O$_2X$JdwNG5-~Fq4|~k-BbIe$lrYH1Dvw?qv!dT`SMa?U|aHU3lYiPhrpVx3Gb1{x8E5hN&XD%-e0W`kCBTRC>rZ1Ml|yH~=%`wCNQ zf|EE~ug1|Sr~OU$krQz5zYa$ALX{qXaj5}>GIlPaW42))B%=5%e_(z7W_3M+ibo0V zZyHSwtMmm&|MhQ_sy1PM8 zKtQ^?yYF+}@BOX2*8Sf&pQmPK&)$0gcHBJ@ta%Lx1!jO3*}eI#vYi>eo@dGZf&+4t zAU_rGcsec|WxDesj0EnB(VuqT5dDd|8%33dvNy0uw6wHH?B4;|l1VfX{00U^xmYXY zR|%-HD=;2Sn9ryL?9oMFZVmDS&i+A+6SWBSS*tjnAK|%6T+-(gsehpvIxc(&8g=G2 zXiP)VWZYOx9Z#^8^p!l%hw~K<-`UAw9^*&j`Ii*6o6)>|ItQyK(par^CFWRu^MHSA zxc%?`rSyx%<-mJYomwD$Bm|?gyfr*?2kB+)ta4V1?`PjyzTH`&!u7>O^6dk5QPeo<8e+G|j0wwM9o&{L0Zu{#4t@9q22eIf9Kq4*z1?k+k2|keCcq4%$F0Tt(5aRSpc9*t64#?*I=GPC}ORLV*p@~!?X6U8uYv1DUN_U6a;ZAT!djs z6=yD-iTG@6yp12XWc@j%7&a%5IDt4s*4uzbC~``Nb~GpAVt*#-Y`*d@?@-11COYTO zr3_elRhd8krZu>p`$JUP<@S<$6g%9=+bIGpDlDc!c&G?f()@Tszyp$K0wmQUiv>PJ zuistZzk=Z1J_q^*&_p${e~0RW8I>vRY7H#ndC4Xe!E=Td3~OH5_rz$cFijqUB22C0RR0S zx!GY__1k7qhr|Sy4)2qxqH~cir&vq;JG=j4%xb}9M5ek*s0*tN2 z_LqqLcS(4_JBZxQ^}_&Ucyo+HZ!Bn!8D$d$IRd04(vPGX;7`Iyrb!Z?v+8Ip&_L;o}_14O50oZ zRqZI9vQtN{MhypIfW#dxvb#<9{j@+n`)dr4e!y!9ZzkqUNcaZ_m(}#f7iT=RVF~WD z$a>x5N||!V>;>88`_&g}a0HGb*_n82x=k0JU4~uVGM|*6|D0%0E(%#rf=q~?v#yn> zTWoj{^Tt)21|%YI2Bf3}&JBiUJgGOLys3?=%SKpUdJM1DzB-WJ>v-*Q&*hciwLCAV>ded{gdalOeea=N#fIE3hQ%o*F5C4iU zA#=WRSmFgB#MS85a&St2fT-J-sG(dxzQl<5p{#317|3*gB^`8);VF6m-@)hGf+XF9*=ejQtKzBVt zj`OXCQVd$Xt51GddPPkoffC#*9)J@+bH%Z9u?8iB5$$flP@^jU+jrqLlDcz~pv5k? ze7KN9&j%esiJU=WG$NekhfR{chvM0qadAi1uck!QCx>H1f>=4#WgNPvEoiaQbzklw z^EKI$(tbRlLbu!Kp^a2Qq@6{P?+dOw;?1g(Cq;=CvH1K>nF7T#fRDzR2#ketAQaS3O9r5KBj=}3Dlp}pcy1(ZX;>4#o z11OL1-{*sO{t{(xHZxBr`BJZsV6TIr-HHSJgnyod(PTW(9uP5Q{#-jI2h#COd^c@4 zQk-i;wNJL~?95?-7bkg{_us%)04$&0Y-6u~21zwh^C6{mpP@DtT2;@V68#!Fzwl3yq%Ydvb zi3|jQ5tm^_Gigc&*lYpUevo(rm?`wLfFUx2h*5(J+e^3Au7fPzx2+-=)C*(X94*~s zn1S7xUIfZUF6gxx*Q1rAGllYh-le!1LMYd0S;%uetl6_S~nxgI+^5ltWCTnQrslUbIg+1N9FAy}_d)15nBwf)xWPao)YPBsc>hO6tVZ1?K zqKi*?;Y4a;xtZy&J^~__g{YArOl60+6l+78W<*4n+c9|(V&-=g^oSpx#&*LJ@x2_j zMtf?k*A7#J0EtDJF+nGx+Dt@)jV7?m4Zzra&cWZ$vf;(cmGj*Q`YIcK@Hc84FN-*81t z<+$$rSUgDj0T3PKgkfNG-F4nNz+mPJe|a!!fprG_N~4pxU&~&=aZsUsK1W!4N{9+{ z>Z0A!2Sk(8!XL9)UEH#vj~$ua2*SfkCRXWet~9?9fWs=qL(hM znFAb{)DC7+5k70-H6dgls)WUaZe897AnIy#QJKE zAmVTNzue|stAFsgcyNeg=%P$jmpdNub1*Y2N9)$S+f>H2BxwZn*@DzVy#fWmquYd{ z;%D0#ygGugppl>ew167z{_scy)*3%Y#99tgAib3wGKQyan*v8Rfy6%kJ6-4 zE@F0YZa-lYNkBDQh76^QHNf;SPs&tNPred1s?iG>LW2Jpb7FIL+f!S)BQ7 z3(0l$(XV0@4E#6q8L3^_w|z5h1~P6#siO}Y=h~jJlOdhMOMdy167D>yPw-@* z7zM(t4;vd+qE<)Uf^$ni;}+ty?dbeJa1U!$jb9RJkQC-9@ewd+GlY1K)#K(HTodOT zc<{wU&Bz!;NHYaj1Gio+{)ZD|s@!3mZ;#vQa==`8km%+zM9`uvH+ zB6fl(uSTBrL+uZE8?LU{-ac62i%#F`^ruH#tm04{KL~$)rnGZe41NBmyXLHtxv|H$ z62O~%Ppa~f%)rI0($C~@ByO|XIY?gSoO z!Rv5CdNRCtNig+dqQa2p+o1asc9rL$5lkX*3bFuBq8NRVYK*2ztn# z?{Dy2skZ)9R4M=(?`w1sz8=h~C^eL9M1%Cjd=&M{I5~GO!q{u;>oQ07-MiZ+ue%EO z!7Lse?)lG>Ch^&n*4qiB4X>8pPqAvWJ=xGFkFy{i|4ST*H~ICO-A`&KDE;JQj{D^B z907ZKRJN-o9kO^TQ%okF@uhrtnIiJW`v#K;Ml~iSdUuI#B!J1J6c(lPUUkdCZe;7t z;)GSYv2i13sDM+Xa7C3jNX*v`=4xOI`qZ1wbu#KeCzkjF0S9}1QQSKSr!CI#v>q_{ zMfbf(a7xgT`OERT`0Hlx&u^N8-%7_UP8%Ie18=`fBv5$l0~YRBfCe12c*lU2p0?~t zsZK~I>a90J1g@^G__4|?3#zKB5vLu1)rlDx7-;bgq{k${jck;zB>jYg${5_r$K% zg~jjq(CmZAAl67?{%Blc&D4iG%NCjT@*|;X<*;z(jc?)XOVqo*L1`K50>IvVExsbvUJZW_V;sE1f- zU7 zku5uQ`Dj+_z9`dJAG_e*yc0)FYK9wo8dGjz+(Pf&Gg8O3!}ncpz$8>%iqVe*Mx!9VPGG~xQNCPrm75od0f3$2ZO=g zu8)ih4jbRDYm_9se_C-SkNc0Bv;nPq&a`D=|HXEK+&^M+VIg7|c;5B8+%RPTq`wdt zoFRFyy-rzP0IoDxqinf3)N3&~m(%6CI7o-U!V1+|>)sY50xKo{Hx%xUI1D?tHt_2I zFD75%oMkIUy>K3`h>v%r(zIv!;syRN)C)lTU)-^a?dM-f<(*5+6r%w)H9CDXO{|n= zBh;CQg=-}FX=(AnZ2SdIv>V@yIq-S;tiFjL)~WY6w9ZJS{FESfgtpPAaaGZ29~6YM`CXQr?_H@zf@)qRyHaN zMoZ84+&Fgc#==0u60!p8K zd~ZIdUZh)Nq{n^Qd88XuuDti5`is6A5fTwr^m)hIV#)mvlO=gKh`u;p0yf`M5i@kF zMb!C;U+tI1;*KFPjtoAL#^BsI^@QBJY%~13-3@rkQ@>AKovGoN8YK&}A3h{{d$FS# zM=oY0NZB)gQ&R~;ul6|_xX5IBO8G=kC1tBJzS8Y0bLW2&v@s=N^lAHtcNnHGz4TM% z7oEzd;Fi|4m~#w(S$y}t8UKM%1_2<$AU^1!Sc|-;ZDjjTGd5pu4IlER)td{PQp@^V z0F!n~Jb#Fe#xj}pIl(ETeDA3V6=9x1D8*}FnLu1L;EQw(1lVRM+X7;75>A~ z@w$IE(`e(r@yE~&YAK~W6hb}UKz6>JPq>gO&t(72VLU*6GMFU<)=~Aix>T8@;lXwM ztNE*?Bn*_CPg?p5itQWWxnwh&BKqY8Hp>)Pt@g2!2?PFTR64?BpFongX-C2Wt}y^hn`9sf3ARzUg;XBGQD<%AZp8eTd=X!I{`uXB5kULHG`83^U1oDXHdtvAA`yApiisk<^H%~(z>_v5&NiLB;&K9T-;774pCoW!bq%fm}WWXins z?TWQ_6>>tsE4w4$F#}`iPOn0Y{Z&2U!>x#V1~-g2nF#WR?_B|$qCp2nNX-_vK3@*e z?`3()4jg^hQ$K)VZRIjL^Q}YMj}t(tt5*4C z8uW+<{G;*bp&fi+1W8cI1cm5w!$8fL%QHj%-5&S;0*Wo+a}FNrG=${zLd!=^AY2m# zCg>^sPJm})P-PZUB{lK;<+B?YOCSpXf7wNRHlvNIan~3(0`rgW>2>o$+qajbvZ!=_ z`tl+NU>+0PzWRBVY_o?LnXs^Bjh0YtFvBA?i0%P2jip`so$U2 z5_OJ3BXb7-wi&?P%@WdnH$m=-3$xSC<-2I1Ke8;iI|GeipU*myO!X0nMeOJRO2QB~f!AGQ5kSu0 zzdKp-7R;M|08*S#UO=d{oBR32EoB?DVg*>JOl6nM#1)I?V51S;=bBP)xBOGQgUiGN z?kMAKQ8vX7&(|jb*^Q?B>^UdkJ>@TY()0@IHfs6;trs~asR!_eSfg2T+|PgPRyspg zdPUS9n!1s_$w{+P&akTb>C;N;e)0<6c$4TYWw9H6sbwZ>_rJ5C6452cha#=M4@?a ztI)MUyw3~Wrx+%6Fc(b{1ZsD)u48vCh4Q=tFsPuUTUvTRJZ$UvRNJ7Rvg$zxpJ8&0 zE^w^`AO|ZOqRa6DM}y~A{sXz!T|p|JSdjzQ7MFm2ux(JOa`8#wb=96{|BzUj(sm^> zJZ46@=4QKMde#Chrr8*E=6bJs112#q(n4Jv*C~fPbS~gJ-6JzRjH9zO)gH4}d`7JT zp+`HPft{Mt-nG9Z+eKUkrP5q6ZJLSOkOe?<;yzE=MRb1mxqG`^EKIZ4S3J%AHTxsi z^TAfiRbSSL^Gry9y#|JneDmv6Cm;C*TNvxx$ZOchf%&%nTTTbPIIA#HQY0D zO>L=J&90lmPhc`O(hz>O^l)>k6SPPY1S{)B`e`b)7qX(+)70Vq#BBnGStR=ld>9+K zWiWlX5MfAQno9uBUcDv#G(Pg~Tf%qk=qYrBNR@BxSo}4LTXYI&n%+rKR?7XfpUlW0 zG*2caB4WZnCnO;g@x-lUq6va`sz$zb{PqTY>kUa9}knHgwomJ&@Fr2JG;EvW)#wp>&0IIjoQ?J zEJ)!zWg0{KGl87ypg*$&ED-R-pC8=+5#m9T zz54aClN#!WKR(GGNU=61@4CNX&U)z}%~`hKwV~EOjJz7Shm+14IXr^O)Z#^TxFLc6 zx;#@wTFhO45J#dqH}F(Cp*ic_CISK9(s6C5>9xs(Y}%kELnSN_o<6t^fUY|NL0tdS zvhP0I#on}v0UY7Tj(#qZfhEpok8SoyP@pq2&$W2Dwmx3Xukl&GNqq6#+&tdYkX)he z@wmbtCs?;248Mxlnf~fw+?B4X#96zXV9*O(T-?i8Q+8LNY7K_h6Y+Y6>9q}Y^gw)!-F^Fwim&(l5mhRa?1ih2I0xO?;mr#zJ&NS~4DN{j4l$tZJt*+9`j(mG925 zfqcgg8MFJa%bVRJiy3sgbwv(D0l6p((+uanWhuQ11FBxcQtc89X8j*=z;~Xi{~yr2 zp&h+E1&km3LC-+qT&SABn;+T*yn65}z5*mT0&%X5;Y1>ymmD1rKe5bW^4uy7stXk? z))>FUxOw5G{Ml7-RkZDjZ|{ug4KilNeg1Q?Cn!0FQGmDajHP((q8{Im8gluD84-QU z0N%-v)|MhOD6+izYTjLR{Phum?K0Y)z z19=7CPvSO(`4_4;iOm18NtjuRzB&iU!WtN11X(%y{hbfQ>#bOFW=#;=DH%$ z&B0*0@t&S-N2>-MXx(ZR2A5W%Y3%FR@%=<@)+^x9cq0s>MmYLc?wu#(<~;kpX93J3 z@s35TTyueYFpv~iK9lLh&t74thK^D7D*#kM6k5?Hf|UM+fiH5F51TIDpFNkq!%k~Y z%iP<_x9GkU!pIHWz`+D`7|!qVK19@JiK=eb9#HdU&@p9m zSO9Z7J;3-Ki|**?Ms}Y2J;~3if=A6T-$|KtUT5@uFhZ~U@CM%qnMjug9x3Dv^a2vN z?Rc?$$UUP20|%h!i8|lVNJ;MPn$#vdQ*`6k=<{>-9X!1 ze5rP-3?X-VK;0n|gTLIChCeW*&BjR#`qkol>2Rv|e^ST|7e#nEdZO3Pp)CYZhvTcG zMHYuyKsN}{n6%@yAhKSF>fG#o=G@3F*a9&7YXHI2Kj5}0$gH>!DCIp~qjF zU;ZC2(*Vj{7@3_QL!iMLffWQcZbnF@y>OKP{!9?(c;D%dvwHLbi*BLsHe5R+C;%S& z@{~RG=Q~N~)~p3`nV0Ah4GjXxN9;07LU3~}iu?>?p!HDg{q`&71VCcKT2NNnd6|X~ zVf>sz5$V^DA^<&yo_Sc{mjbZ;I*O2$UC0&!+yzwEIC-ut=Xf z;PqR${^;1NWz9yC4GgZKv+%0<5=3V9RJwc96HS(Cj zcxCb{nT}MKM$O$XMW6nuu=2nfM4D0^1UI1VF3;D22c8O4H?S`M)5MkO z@EMmAK#tfW=GnsJ=#0BX<(nm5SxQZQ{=A1MpfF$9Hfx(h{HECh8CYC{Uon&+(sKX6 znld(2|NqG^gPz>HXn>IgpZ>>T+7H2P{9W7rPY<`Vz=x{T5Liiax-1BmIOmgK&)Qh} zljf^Ol_Lc>)4;k?^@NoM23V4c>>g!t6j4*BPMANa-VE%TpIn793n5U6T+3*;HXqaaDH2dtk!&9Ne`Vu8w&7ju`UD%f&~H9Ti-3CKR&OT7sy^-NiY@vP>+|r z?9?x&L>Yn#Cs3etwuo1>W#%HVq942g-d*LftChxT_~#0vR1V6@9EXXaMqQhAo!K zMzDP-Us4Hj8ST_+Y~Za59NxXRqoF>NNb2@e>%y`DMLsNL=b0a<^mTpY~;5M-8k`c(5_lnS#J+N)Z|9vzQU;BaHdkbIRbodn) z7;UY7A?VhZf%&+|ivUa@@(sX&(Lb0wK#GGNB6mmlJS%GL-;H>XsZsn8V) zz03!C^4w@{3yll+bxgdus$fi5W{Fpqe1e>%i(8C2RSJ`72!>KLqQeITU=x1Eaqgd%y>Xb@+7Bl~B`Nx);`X%xFT?7)G3JIjsKAxkVETcY?1xp*7u~#prPVATnnh z07DFTEeAw_G=c~W4y83cV&_MH+B~>m33$u0SsttK62&f*t8wa0xKDDnV0xH395yU@ zaOX43ixV!*JDuIa+*rz>8Kh_h|ranr#Aj}Hyc zPdE>(5K8*|nf(F{#&_{2K(q>FtU_7UU$in=64~D{P^Jz^CgRTABKVFuW~RF_+H*Xq ziG;@P+U9fF{3F$((&f^@@I&LH-Y@dh(GDN(ar#vE=@cZ2X25|9w9vY`BTzMeS}8g9 zF{)a@tL2HugK8_LLVt=Z2>Ya19m-PdKJPT+M3P}PX%z&l!tLbku+v_1!X?!~Y27+{ z+@g{@ob2Ue=c%e~Kjoh%1K#JvZl|Pih*vO5F>?VdMx-Aa(rrv7L|ZZfiT#dT`&KvF z6a|X6h8of}q>b^>E&mmkJt51|Iwbq-P}=m?%Pd4kUX@Et)(A|I{G}-lPzX;XN0e(i z^BmEpPddG%x4U|R9ZSf|uP}k*+82=Cit@5i7pHmUIW{=h2?&yIV6x?_3{DsjSNW}f z+rGd$iBvxTnsmS|Eb%GGI|wrMLsVf;?0Y|Eop(uTr1_#}tQdnB?y|ibar?v zO)Yj6xFc$`I%)3235O5LKnkMeA@7w+5Ih~>7=AAjJ~b{-#aB z_RBn&@$%6_o-KjlqUSaar%_WazNK$kF+N#_ggNRJW+@L^blW$Dm@{b2BTViS@+ z>EVoWn!`3aB#JwHt(lZNVX7roM1^k>@dNc2n7iSrS z^9Ze<*LQ8h%UWogvlZc&N*esBPZZ(x6SXggZdQhIKdVR_U54Q4r*}Hd|-s|`b zz4vdM7!&nxv8vYY`6ny`-qME8!2?oC@l1l`XBll8VKpND zyY4;glDB-uk!)d0jI3FJ?<50ktnA685~Y>iO=sjnwc73yiB6&8x6?vL553qv6V5Lf^0p=oYCg+c*+vcOtp9;ZH-qLup))3aV{9n2jUtibhF!*9o7^dgS7A@xK7$sPX0KFb&K%*e+HCN` z1y2v^_teHIeKnU1PK5ld6jdTbMPa?lKMhoDGMo;a?%y0e)(gdM2&*q%A`at5OaDvh zL-J|n(W!IT9xg#W#X8yI>E>1TD-?PDg7$pI&d-m(-d}z5jDIhk`7d968FCV#e&fRH z!Qcn4R!rJ?)k5ONe^}aP;d!ncr6b)UEv6yS%!m7P;l6q9yJ98)!mwZjz`h^ROO~?- z!VV1$3BKP;13AOx-ZTVXUV`HM)3l=7HU3x!sHyR-m4?l5MdlYC67b6-aY^W_5635^7oFu~&)ST* z8i(ut@ZNb1E>5hX*L~7A|1SPuIysv>2%?^MgAd8_hzr_h88u9~j779w^o@?rL(v^G z`lR}&4hhNop2(cIkneZSF(Mxz?H|k!@Wb0E0RAd84Je&<(B`|lfP*o;4X22dZ>W`8 zN!WUcL4VkvSu4|+# z)mt=n&o^+*MN#gHiYCpxX!@1ZzI_844gTEvxpk zZ>g}|W(q`37X6$nbY()s?h6?8797aw?$U!f@*tlI{eWBynkD-KiI)u$$o#v3ln3z0 z&DDx@yec}$jP*G?1fAhy8s}5k3Z{Q3TrKr0 zyX$kIW!7zJ_|6)>y-0%;Whh{Jw?-O^t6}($N5#&WaU_-BZJ@ll0m1ro&NeTT=>$Dv zdo(i)z|HQ&IX4Nxl>yyeG({p!%E4RtKT?W(!724l1s8UySj8C!CI;$#5JR*OvU=yJ z1s*!M{!-L9U1w1|G8xR(HZ2i-OM*6{UP$6~C4OyqBdGbzDh;)K`mD`q`JU z8dZ3n{;6_BkcoY>SL$J{<~)vLh^kpNp)F5ZpOSJ#-w}G0sLgI@oSZP>7l|#{v|C3~ zF(D6GE=g~kC32k(%@`rSt@dC_@WL@_e?#-3IO|L7ol=T5A!xr{-em%+C9MgjSI!n)Q5s8H8)0TAw4u88{goZEBVS>bIDq@cO zt`4NYBp(mqoEMbfF@*+hAX)c^3qM-B9IMZf8|?^AJ~!q0y($3q>5{~^nF~S*>j_>5 z7eowe2n_WKDO4MukdCW-?_TJ%rUD{w__IXc3Z@Vf)S3dYj06~TzZ*gO&+;A~wL%EqI?)$)m=j8L#GR-@Mk|5vkX@uY8n^XUn7qY^W!LQl+572!Sfq9KECR`~b9I#@pT z!umKXrNC(ccNOlX)M9Ou(AdY++ByoFhmV1c+I6D8{yN0-oOSQ`A2>3i`DTwrw2Nb9 z9XC+E`}?Nh*!7$~Etvy`OBA}14C=YP;A)I@q@b90n5-5I5%ZdL*c9}9gYR9z@ec-0 z|3KEt3g)NLRJd(#1Ks-N-fY?1eRw+zhaA)|*kC73VQCxh(*LQ8t{p%gkNSC#rEIuYehtTBL+RAf+XAr$+&i2x~jnt?Sc zD{ti&g5~-h9%rr?%xzUn(nm(?xp3MaId}_oh|gBpLtmxmsvue=>hfFq*%j}!svGyX zSY`~y+U$5J6ddsj*aaBgolWuQ=f@w2+aflQa>+# zai_q_7b?Z1oMeOUau(QSHJTz6u*8?Q``Smr3^eepJh02ka#{-{V z1@*LZN=|lZ&Y+j0XGz*|p9nUg|VOt zMLo@QMn39qX)resCNV3l77b*d$K{(6$%if01$P&Sa|dT@VY2c9gUe0eiYuQOj}!fXiE>XcHfT0mD!vZ=;{li zxwnu62$MCW`HC8*8pw-cj=)4qh^+pkvTcGT;0NsdE{Y-;Qf#oVzLkCVj=LXt2Y|OG zEB*|O>nQ?L8MYjSPuXFz!hF*?>eS$)gB?MP@royzrUvl_1swBgSh+PNi)`G?Q7P!# zK@r1te?ZBk#CEIl0LF;Q*qa4bM1Ms@~}K4A8O4BaeraH?;f!Q z86y#icvzu@_29@ynKhn6vseCRby2G{@-z=)=6dIERHsZkBJb53%tJCJ&w0B-$0c*a z-hP!%II+!*c*?GX)R^<=yx-d@lR*aYz8`ua9)VFA)ZFUn>E0Da7Nk&E6wfD_t7N<> z&bo2p$yr$+KoemVyc9Mq7e|XEKn%-gItiYv3DPM)r!s4h2EJhcdC~qsDLr`U|MM4x zMKYF-0~f;ZzYDQglJN*G1aLV+?ncg&Jg4F1)iJm=X<(0W5)$%RdlM(#)mICq)^_1i z7lJm80k0KSq4?)KJ}dghk-R;$o?)-xvyU+N4aS1XX}^p%e`xu^#*gt|@T>)YOLy9O zZ8Ny-|H81V`_qs~lc%1Wzl^SdiU;(u02DNs{J~WG4bg@+8yebcJ-m-c~nKO~F@ArDD+=ShZ zY9*!rHq&gh-8Cuo1zwtAFYq)3M%B`xLTXM)M0d`qW2bY;QbM#DJ+`R1#cv7C156t* z`{EaBby<@5IbclD{SjRW{N(L+PvVp(Mm}l~dI%PwbQS#@JrLo9e2nTqrXWJpT^y*H z+#O|s@4bs#39F-TcAQO@^@lqGmb;ZF`SMhIeWVLdz)5=mfRyI^(>$ym(_m#HZl1Pe zg-;ow_X?MRPafQ>D3B8zQ6){Gfi*ECkvmm-NhaGVD>;f|txcf>eMp~dDR025B3gm8 zjCKe#!O}n9uoJA+ir;ReLIVd0^dW8WI_?LAX+v*MvGOR!>P8)%zlueLR20Mf3g46J zLcRhBf$(dhd4ZBvxc}`*Ow#nlQYF<5^E=ul_l)L>{n#WqS>ZQJIiWu)+|*y6!u-Mi z6;bHGM`%#tvEFu2-S^ap+Mg|u@7wKX>Opkrgrkc;LuNf}-g_)x${!f&5+$(qJG&$z zpLRTD47+ogX6Hl{ys~2BX+{8C=nMd{wPifX2%s)2RN&R2(yyYWyi!Uo z>wqFQ-q$=D&>#a;Kh*3XxAM&w;P0r5q5pAr}uYwxY=POGg zK5KQ>c9|?3Dq@PTJ27|15+m=>dZPeE5d8ht)Gv2b=a>|YYQmF{^h$}8}# zY%xcCw@P?b`9k4_dkDHAp!v zij-LXYv64)kO)B8!XH9`oN70dTQjtxkHmYR?|4H`$h#Noy$-f1Z+D`WHb z?1K@WS^UmfJh8tPK?NcH_H>&<({o*+Td{%8*23qf)Xmx#44l`hQCvK5k(o|1ldlEB zY3D}ZC|&1%rLo1RgYT44=1#e5k4sWBP7>Ze6ph2xEtgzu#p@nW3qS3Glgb#^9_&HB z&b4|Ds@d^Im3NlyZ7?-kS^C0%oPT)#62;5sW!bq6P3tq|-x+-V5v@o^c-T#%E(L|c z7Ds;1dOgZpc+9#cr#Wt?rPevoQP8kN?f6_M_-sS#k_W!oIeh8`xYs6>;N2t0*GiR@ zEC)7&3gw>~#EvAha5Lrqi=EpNaKFJfui)4|eJ<*8hllNBh}$0T=HxIT6eL(!Zpxvr z(D*F;o*8&sSiQ6m4T}7j{rUZOEg5nN%%9j_MsK?U*FdrDbE3ii@3DjGcI?ULG(3vx zZV?myx0vf!FD+h?dKteH^-|yKzLZ1#w>QgHqYpM{7JqOeGL9aQJH5VD`(qEH;z?gL zqig7uALJw`)lN(L$Y+eoKzHOC>emG0eEIMjQ%*&K=_bRx!WrSEkP40rs=^& z6@iwZ82Sz$krY#)CFq|6PeiilRBCZb?8U>Z>CI8eOT=`D;wfmY1ZdZHzyfPurp79_QzkSgkAX3Aw@-f1HVLmA$GV^EH-DK6J3Smb8BQqW| zO5eftIa#InsrZpZa@~;A#%Ba?PFD=v>!XcweYa<-K~&t)k6UA?VzJ}7yj2v19dnV8 z4kFIWOJzIWRl%$AK(x#C@wNTy`ND%omZoMbE+1hXw!G1Q8+CzUZ+tvfg+su%Z;(>O z90}QbKZ#-mglZc!xR8PO76*8r5dn9w6H!9s21R!bWRko{HF()q;6Ou2qMGI5VdKH4 z!)NuiE-y>w;J)RiZT4G|fSscdRSz@TfNm=qVqnB+QH81q4~uSJC(iR4I544*+vNa2 zN00|HhH%IAp(0M!Aqe>w`qe6v1Tlpuac*1!of zHHpXDzuRc)_@OGoIJb9`G4>o*?mH%Wo3=s>{c?kZ1X(W?>f9C#oxBxz;Mo)m^e+>Y zo1)to(kh^o<fkCC~)~}ElG@AZ3P*64lZ%TH9+Atg0ETY9bXvHNDbt$w}!H+!M z{@%G6^bWJZ%zQA{4x?(^EPCGsfVQWdCis~Bon}?>YLkreZNg{>hCux(TotYWI2k9rh=fXi z>soh*zN=5LZsU;ErjWr2}C zqY5%4O-xp0vpLP)#+QU4U(xAdwW(dx*7Rvm1vGIgerwq)K;L(WvQ8ve4O1Mj8Z*7SfwGj*(AB^qndvJ)7=f+^0a<6EQ59H? zs+~XRupvh{OiWA}fZhW2r_cZ;rwkxmE>co|FaNiEwc1rm6^d0^p$8{iZ&gu-c=`VWmue{i}=YS|4xo^}=yf5R~A6@DwBG>38oZB^X4nQm`VGGxEf@TOHkZ7K1-QYQEGiv>pG3~ z(pbq$WlZsBSvH9foy0STi;^_lO!gnSD+*q1iRUyCMOXf!yWj%{&7>^$j>h*ts&)ZE4N2pOimJ*fZcPwX||IM^rvacjerl72nfz zfpE1Efg@~yY# z9CHNaT~Mq<%fyoV6B^nDjb%&_oLkG4Gwo#3Zl!TL$|%U9y1%Yn@*pDxguyOQALlAp z$3*O5B8{yOZz3f@0WI0!N&v)S!h%w?*9d+e7J`HYb`AEM(92cUKo2Nte(?os_$iJo z1}Nb2t;X{}YKo_?By}Q-d3M~l+#@t@+uM5)v*2puQVZQwB3*}Cok65*gtua{Nq86)0&R1_okA^0DM5%|2Z~ytR)yl{Y?DPCmw}Nok;%(N{cnsZf1i-ni zOf*n8UkFmT%U^?7>fD5Qf*m4JMWpi5v+K7*UWM@it2C{6nM= zg{=4jq4PGzig+)#qyiB;X0xy_zTD9Jt^qL`SaITRe@T3+iwEVW z16X3@qbh&=`U)|C(z-yqdb(d$l?P^0svI8e8-=`9?cv4Ha^DwP?vv$AzKsy6#sc=q zMnB6BHoi`P=i>U|Q9|y?NOl8^bf6e3n8pM%J++bmx(lDnzL}1?>Wu0YvMeEAcGvem zneazz;$tEI?9mtGTJ;BKk)i}H@A7h+E1zgVLpx>8rXD~e7XDy+4}ye zE73LJ;aQ8Pd;K~hCABu!Zp{x81Lsy|aW0!DIQ|H>d;fZGlriUdl^xV*6gkhUM77X+ zf~RIl!rIS%vBQrHP=tN~LxHZ9*HW>hG2mScA7S!6!Wa>KjLf!!0)fy=c;SWkAi#a! zDS=x!!xHb1tAHDNo3%^7A0cDHwV{FyhhAnrF zjz^*&CcU{vjIEQ)S)s$(zI9BLdiZ?aSU*mY$~;WobMDqPYUM|&Ee&a3lFGU5AF98$ z#{rXKV(@n|Yxn6lO9#@LnY%W`7l%$+WLEDd_>wOxE0k5%p2XIF<(gJrxwj48}^N08b(X^hv~|k;VNwUl2~5EaA4m%q;0wT@VjM z-_QUrfT(PjFSmK2IxdeOWARaB$Hmngp=p3Ykt+U3kn6Q#S>fN;Sr+L<%(ZE>^}nLu zu8<#PhJ@=~LB7PKMz`xH8(%-%xwbU5DYJ2=a=+eMxOJNyvhDnfK7Ji9l1(NG)4;sDT%^}rmd1aWRI(37vxCZIRNg3r2U+Zl z#u206UR_&B;4oZy;NnVszz|Nbhb5(3ja&77VgjhI?TSK0=z5!y?GAq`Rj*|**qgvW zFXf#hrK*}5{MX#v+#8@$q9{CNSG`2GI|TEluB)P1gpuz-{mv(oMX`ITKe9Oy6U+BL zu1bjf1#61`)1%l)g1j1vDjLoG#&1j9F9@%t9v7?%lbr*5@)S1`ipB-NA`a^a&>VpH zo?r!ykqA*=N|)?+PTSF#3?fxCsEk^~z}j*XZ&XlVWZ971vb*kl+)xwpD398OTv0 z!~7??4A{F<6$@sTH@m|WT}z$q0`D#n(HQZ}uOoZ&l7D)m{NO|P|7uQwiahwo=|aAA z6v->^J_Hp%chqm4_Zt)1~ANu0hq)v-vdS5ge-#DJVjMfJOiod>y*r zRxU&w5KLj{g4~5*Tk9|K+Ka2hInzJZ zK!S+*S*pa$nCOjz%pC0vLb$-2PLQ|-|K2J6BC!mFh{ySF)rML%dcaCuJ&US7YvmMc zVzb8}G?dPW41X=3I*gPqqp}`v0q_CIn0%cL*LiV=dJ5kv#F&Joy#{_KQiw7*En-N% zp0ED2@eJuic)&WV0qZqn@wP3dgq}6pGc%Kb{1cd39{Z4^qF=~06g)&%(>7nAbKY8% z>RD}_tf=x89AYp2c|g4fv#51o3}R6$e7)#IAmCoT>D>hfM*cKdm$Kl1r$8APG@q0W z!$thD!R7mcCkMZo<)17>S}xD4-ZWm=td=#CaMpTUG74`kjLesnI-u%vR^R$%sg6~s zkubQVpfDo$M4RJAsF5{qREVI(FhSj?8Rl7q>`&g_E?#{N>AA&vgwKTL;hEej0~kmD z*eQ!fhBUa9Sti;S{o90}LIzzzS6i-uY4(E-NtVjsw!?9QRR{_YDd1$&Epx5HTo zxSYTJt=g0i0@KzAI3F;5B&Pw_anvBuUwlf;RcM4oC;D#4@niuVDnrDv4#@yn`Lj}= z79WdlJsLnsx$%pEn4C5B6$S=R5&Q=7EgUpFjiP)QpgY4fq+stiyB=A$znaD-UD0!U zB$}{L#N}S&wEn>zR7YYzn?n&!Kxmmt!a5VG%R|BP0nIZAa$s2@-eaGXCnL9<@{bp> zjzs`v%d0(neuH*P{%YUDH?So>M2Nl8@a4uFb{s}Jl1_xG!4ZaiMi%5n#BtM7v^QlG zB8DWl*OkrTa@zu0F>^zAx^oJN!K#c)_}# z_2Mfei$12_cw6o&W{CW1l$G%~c|AaChxC!Cu2r2Lm|2WE6OLt#ndILzTehIy zN^qk-F*ZSCyg*~S{R_PLrXX!SPR@!?$RRB#ZA6I{yrJRYV2(=3j^Gl41jh%h?wnCQ z+n+h~(IhGRKDp*Uk+Hp!|_i(}+9bdfw^QgxBH=a`;wvqtFFOOs~ z@X1!-lNJ8=PyVew1pQxk!Ok9dko>-FIgCxzrKS#w zsPGq&$-fG0c^r<%c)c5+61~H4+Ad+~(tidoMj3xE2a{R9=YTaqntEXwI2^eF+L3^A z=O*v_gAy39l@z{8xZVBKvx^;Q|IqHu+x~F=-boBRmLX%#xw-B4fy3TTWKhtzzjMzO zS{z9LTriAPg#xsFAXSlt|BLchO~N!f-G&BrNw;&vgD3JW_4A0<=@~0dP)j0QovhgZ zu>p34r*4SBRT^O*PKqmXb@T@fN?x?a+&;1!fXzIm?RAmOf{_qNCxh-wK(V6O=ap zA*)52TQvjk#(Z1dg^oP7Db!0P0CzOQmpn_5zk|XZ8LovYke40M@S+YQ{C^4`Rm~Oz zRB@ID$!zX})SU)s%XOFME!@G|fGPF|PEF6CeV*TA;KlCq;|w2C5)rSLkXXyV>Qu4; z!n=ir9Iay3og!iafkM-Eapa@9sD4GGHJ8@f265&t!HkOT9SSo8VwArn7(Ly4olTQs zWabt8V#{TQ?T`N?UV_1W5uN#XrgwLjBv9Vd#HH;jJ{hf$6{NfuGG5sC=4k!Dw?95gePioK zMj`*FY^U%PcI;F`zlgf)m5{S#{R?*m+BK?;9P7VurFJ!E5teEp5>TZKV4& zBZna3W%w^Os*(Jt|Nd=OijRC~E_SU6vn8FlL$evW`t!*fvCGtMOpL!)L7}v6NIUy@ z6_|b8-!wGJj^o#MXd5rm38vqMIoeM@s{GG{j0XdxeJIV~j%WI%_OC3!o{?uGNtAgs zi~{_d+0Z%@z??JCu`Ll#sU#>la6yq}3Lp6^!AfyPpIGgU~@yVQv9bvzcn|n@`riWaAA2SehN*vzBBn^tXRG1o@Y-*H} ze;j+Udv)BWMs>BO=`v{9?L-h4id9s|Q`0Xd1v%lh52cgBhQJ=S3JlDck0Y2_; zY(e615b8ku-wD{1?zV1h7UY%^3*{YE^Gd4+HsDr6l@-9vVr>>(LOs%3Orj4{Rto@z zSmMe&pf4Yg1Y1q-9Z;-bz668&-(UDI18bQTA~R|~RY!qU`EwhDBbT7`&T=V zqZYo^=DTx!H5dj*AxB(Uq7#LT@6=lPXzbFHKBY*xx|DvV`unbf>~p<`_3*idvU+Jo zS#&LapHq=>im+rc&8K;yb1lRLo9@#=MAqYl)I`Hlrp=AzP^P~Z_b6i=-QSVREjDSJ zf$bjzXa;2D<#F~I6XoR7IFW&ZqhUUa0DF-3mlf{wRm67A)0UDOE%+8bP}5g9<*I|n zL=PGn#w>z*&cI3kd8D(8p*cagaT}vcFUp%TrQ%?A7GQ|0zPk4&*3$m|Cv%z>-3h+ z1e*Nn(Kys(AW|X?F&|MuN>% zc`sf){U#ep^EaOmv-rBtu40y1&2K|QP95T)H0$4a`H=g^QDq!@Yq_t(mfP35FDmf* ziml|wr+a7Drh9zLZP?%tvkqetC(}ii);@Zx-Kx~>KA;UHvz%ZuZq#%bf#StIF6F1m zW0#MUpiaWH2;uZAUHG@3{=)o-Q>GZL_QQx4wufid{k6!VP4I(uHktNtQq6G*B)f2j zsnOm>97E%)B(50`QCTM0tj5TJYIw<+eqQMuc|5Jp{&hZY@ygg_3;-Uh#lg$Z??4v? zP7xS=|Ni3CTA-XpBYCXDI}0vs#OsHy_<3M1#MQWRIu+?Xl{brVj$ETV(DLZTT21!1 zA}hGmQSD8=<$7f=g=JpNe$Bk{Pn(!A%dDRRiGAktLt8SstkMKF&8jh8@scVGXAJEn zldnffZ?S?545B)QX8OOlrBSG-2V%3syC%`aJmpK}f4+avVmiPdeeoyrrFOYDbGi7S zkU6_Zm1&?bm@lFDZ6cqD_XRuq?(Qg>nA{g0p0_d!*AZP6BH#Dy(+S;BGLDQqPjGa* z_=BH8pnMplusc3^Uo9hpup24h+os=9f?@qt>E^{}|E0j~oR=1?`^=CyB(UDpCRRi= zP;Rg1+!_2Rt6Bu)bYf|?Ei)c)Sm5^axy~h5XC`I)rG=$1xPVTSG1ZNK0I7heO#TIRI(f99^ zLPDg#G=OKN7>Gd$_?+qPmqUEcD7%Ba#e${IoRY0x?OVc*9YNPs4y`}32RlPj2(vw_Gype}Gqn^hd3{bd1Jxt8|2 zVG(d2_g!=()D?YwKXR?CUb%k%DsuHp^Tke_fDQTO;SA$}bd}^uNY%T)WqXATMxB6= zH~qWqH3LhZ*k!cC3IkY!)YMdH&G>Y)fpIZ1U-ywJI75XFXPdJoBTmVE25WC`4+-_+ z0byYIkZVM=O*VNRIs(!FtzwJZmwiA#j)N8wo1&DraA`Omf8Yb5Z`Nssu=c0H0nMMx z|7{j6K_^TMq$(2b?v1<(^0b@SCO<;`?!Gp=3w4L0N$)p~4?H~idGJxNs9=p}dn1@P zor6U1Z$@K#InO?1W-;l;8+Eu=4IeATd&qQ~VeS;NBS2^pueyOv$S&a;VHCIn4^sR_ zGWqd=9V+`uHSoy>bCn;v?RC`Itmy+Aw7@S(N>7jE?)oIQD9dwb|&lECT)DY5UEZsBjrGOr!-fJuXu zVs`gYZV)6X?VJ69z^`FO^D-pL59G*J-vhv2lIVUMeUNYq>hcFlOZ?}1!z+A4lZS~U z?`|K%>gjF(^FlM%7u&qFkZ3Qbb?tKjUwk?;k~wBOCyxW!1u8C*0(vlqVa%qd+(SYNw!`$1cq%VjjC+KwC9D2URO*vVc(gu?(6}0MM~%cXjxTW!@8~ zy%wg3sc>#^DbDsq7>`PxA4*c^+c9r-!>50bFaEsq()dv7%20Q_{#i3@)!v1GGTJj( zK0O5RIpAX0s9SNa5efX4USe?d#D1lIZvuqsbeiQU6%0a3wArV;pH&veK${xPq*#6Y%dwbW z0NqrM{dlU%yw=_rNcnyheDpX+mv>LXXM)R@f=vy-W*C@s~+y@+3 zsH;!Y;}7%SCLm0TPOq_=cf=6v`(>)^jErc|E^R>k=>$q?Vq zyH#$m3#x9f5_dbK`xZN8((OeP7rzEX>q`9+ah)A?GGID%_NZyPe~@^1W#wHnk>Yg0 z@T5|5w(`Dey(uE$Fv;!BWL(BCn=9NLbupbSh{cX|oU{kGGcG99YJxA!NgzwW;x5u{ z*`xoV@NMkTQoE1Wj{Wu;(Iz%2g7vr_R1T<^LHFQeJmh)1m3%h;sVbFO@>h z*%KM&@ON!~?hHDgBP&hRElmS1FNBN?qn*tJWVMI9Yx~@^=n9Yjc_KCEk9f~+m0l+Yf=go`ThIt5VP#X*H0a-wYD3%w-pNs$!a3 zu0Cg--u11x$sLkDeJD~}g-0cpZtZ4OBqny|8vk{7{>bCh0rIdkk|=(0Z!beCNYdBh zhIxCXw_9ZZ@ioUh_r{=$Om--gEpyo=G{%jR2B_&0G+_Gh<@pd}m48&F$-4pCR(tqk zVlegV$`wCsx;x!nZsP~69kXVfDd?#*f3*)~mtugnUa|83*`e+9u(Hq{+AciX44ch) zG02fEaX|&*9>WK9+dN%#HN3wn3aw!ecUKVsm8)I54&X+!f?z;892BRtGTPLI1`5+j zgk8nV;P?>SHAMWsxjdaIsV_AWw&U;_QB2oi0Y)AifLxnfWmfTRSi5DuaN)D4;O9Q3 z0_GIdo`0V-7vhrXqgY+ZsC6l-N;UeeQ;lRe_v;33);Wp|J>e7TmpW5aVvb&Y(y%es zQ!B-MNySia72;cqwYr6P1i zN~J)&wthjzp?PYn6z0D^$0^NBAFuGcleZ{)!fPK%D5)L->AdOOG~;^4F1^094dExN(;PC6eg_)tbt|K@1WSUr@h}R#`CP573R~ksJ#1*ZV3cHt$_I;` zrs*GJg6Af^@v~>L1Y|#5}9%4+NOZs!n>##5|aFK;22+(9obvX)q*`H*?$B z_-T|gUVkolbsJ3eO+YQwKI?wj>tt=gzJrTr00=c033{}V2((@;&2h*aPIT#MELFnh zEkBCfzzCUc;LD^6EN3L|1S7ZR3VKm&OuBgdIHW#(w{~~2qwRget*l;59?U*&vyfJV zg1?ERN61qH-cKGO_a++$!ddi%MHVwXMoEaWwOSEidciX>n`{FMHyoleWtB z%Rbae&AxBb$+$5Y`+<8>qUK}|!(i&TWZJPzsjl&j?qfwnj{M}|GBWRdVOQF9{koGR zmyPzV{L_XR@gKaWbN=)#pz);g5F*AkQ2gD86k!<69Adnx6CUfCwmTV|z?DKWcNku^2D{Xa=t4P@NSQC||wM z-*U;r6-a{;slf8$K}tR$?*Yj}$Z+^SMbgocbrg^NvIM9ZCnhIDWSzlqThDf=!gCYb zZq2EQ9e=Uu)Q%5oCC2Nt?QdUvFl;O%E4p947l>3g_XLZ|@%3v19|mtX2F_~^7gOlcv0t)(f(Q@qY07D~Fi_(Bz>9OESKL9OS94KBsZw<{ctp5WqWEEAt2Q29a z3t%t5?cGjKi9xK~Sbb5JfDPWU<^GnP$8PUT@RtT@Ga5>0KY3q{OW&+Vu?#CrmukEZzc{wGVs{d^%K(=(y1RNJ zD59$%fPDDLs>GO*To8&d2&V7wn55xsNe_74nn1DZR?8C++f?uFj--2Fz#1~5?$HQp zF%|<75W9qk!Ld0UUvvAuAet=dY$FwZkm}~j{0sYv?s&s_!lRWF=D*$3C z;NFCYCWpJpS78n*o2glOe9_)i;re_MI1-J46<@Q)QICAw&UAJ7{@ZNKipcW`^{!4h zA#-0k_Xzp{&kJMm(4K+zfeRcj0ElxX%wYF20Vv;n>EU+S2uvYvHWQSFw=Di-Ap0G` z_wb84Dc92P0`}QU2>4C(CHitIF#|+s!37gwCpvnaO(U6Qxi24Of(^yQYO*+oK=;1# z2dG*hnzZLJXE!Rv$`rC~flt8mOuzG!3>K7%xf`U_Xx2+gT2Zq)>ACCC%19J?q8I%8(h>-{LuHDo)Ce$Of&Sz!ZFvAcsn-yOA`!)%-{2YLMSk+;V_%7|hBfUo!+E zPa`8E1NK8`Pv&3J2kb%YzD|c*!!j53nDow+q*qI+YTXv;=jXUNcJpY2*_E{)mQ#Q2 zYJ37p0b`##J~ag_bFPlZ$buP9D$n1p!@MYHU+j0T8n+~)M5n4D?9bP>mGystYxkO! z$#i+x`S^a*xn5I_WiaDk0bOYu=+app5u;Ur*#<$mj43%x7f^#-uh!DXgd^QR$@4ep zZC3X336y6kQfSaC-Tgt7NsuBNGm84ho#XZ}AwY;kXXTTNPEXkdG^;+0bT_?oCzwMh zDyjWWWxAB+{i&GWCBUNJm7I!dCI7Yn_57vEZ`jpwHID@Mn!?ts}Oy3hBLy(|@c*F#*k4zGsqfp>^6ajPX=%eZz=KLF7 za2aDJ3y0_O00^a8>{#e@=NBMgrXpkofG`5SpWRD;RfnSKZKm!%Oqx&AqFz&y$j7nN9c6K_u8`<{Uo7g4=z$9KYDb_wVr{Lm`Z!XNBnTr zm#ESUivC#!;kH6D)BEPO0e*YpQvtmxo$*Itq6bajL-`RCeOp@q>^DgFAh*HNtOy!Z zV1<G+`7jG6uNpf>!dfuoN&)(97bfAz;>1B!RL<2kx{8)NABIey47+1GEpeFAuIe zy4QVH+Pv^VEJlq1dA2$jvBuv{(G*l!mW?P7XNHEN)J&l_*rEKq-7amewFCexZT7T{ zCF21P90o-XkDP{jIUFwb%3igSh}$+N&ejk`jjrYHTry+&en&JZqVP|{2v9o-Y1{aE z)U2~Ewi?&AwmN^5h|Z3V1|nyRE$j3xk`eHM`32r;e^kZ=6CQxwk!VwPF{#Y=Y^<%1M_#9>&Ah;^Hv+>AtT8SUpSdIoiz^{pK_Z+FP~;e|4nRe0PVeF{^ygz9RZ&Q78%t@CRB{ug>&11QEDj z;-FaiWr|vJ8B8N-QX{eKdn4xD@zwFAU(xH{kh+A%lBU3g)R|mSgy=&u-g{a-NC@Tr zSGrv0Fow0*wej#~x?+a3hT3mfb#S|ckhC5kJ(vyCzL{ zztwZOHwpDpOumy9TEnW(sg!UU%i(50|AGVu)f2)_JO6d0Bo~5~LPF^`Ez$sxYJflQ z=qQr7cJ^VYU)BjTJhl($OG$l>xuA#SGleULc;$Q8SPsmgyyyERX#{+(XX|a#t04x! z+(Pdde7>F(J}d66wRKPCg3R--INr?tg}`GHKFiA!!)q*^I*2r zrh0aaLcfLLFmWbD(WapBC@JT>X_{jiv|GsQ?z8WG;y8Ez>2Wc^U+bmvGEdCWH0J6V z`85(&wtB-8Fze&U{j$4-C^O{J>AqsW+WR94tpPkbD)aO1fpr3u6a0q8!p9@uBz;d2 zIz3C{a%xW4#8#w2y+Z+4nkV+;iwF@BC@X+`L@JX8W*yptuGd8gdr2lx`c1e!EFVW6 zhkd=>lQc`jXikDMm z95sJKg0diB2-nFVmH8@l#W&_#glVnU=!Vxt96JVvPM6pVU20pi_11Ecmjov(Jm#W< z+~P3?HAM7h8@Y3532~&nR4*x(Jl&a`BW^83y-gZjQ1AR$#4wloqy6tnUX49m!s_lB zz}~&b_rJ99Y7C)ZLOU;}3vLs_H1=^qy}SKc#$oOFb_2`Kx{6Z83sK9?Kx&OL1d|d& zynqs+_iv#xdjSlpEMBUi+P4!b7;tL5Iko}5zJ_-p?mIB|d;%4m0alXj)n8!p<+k~0$JNtsk-NITtDS?UxUNS;m?Qlw8r zBOZ0xIPlQ|)Sxit6@1EEpT3OQv52UAkB*t9n0)!~nNx*b#{ zVQCocejYBL5;nGDIM6WoX32*{em;h3umgB}O^y-OuKO&M(wU0d%dw5OS!`lk5iF&( z$NhvK3flv}n4S$8=(sBlMqcq=Z>QU@Ln9ilxizw*dk&)>#0R|`g&yJ9QwOqERP^-m zpx%R`mkGs~S605g^oDS7U%!6E9J$&!{RJxV|E<+eNU?y8mPyEjEZxGn-%jnlOY|JG z%-_>4#?N}Yzi2I+?V@PH)9kPoSgp!t>Fy7e7lCzDj0f+YS|d!e!}gV}4C$3cyD2LJ zPMnTSL8;vmLf<84u)qwg9G+W7cGP9>9n0T@h?5E( z8NQIR5oJLZtX02jCo%#~D@;CDvvk825753T_^U%n6;)6r9iw)M3MIJ$^v+UfSs><$ z_;|G&&M^uZ*Z(wTG`QvXF4=c+C&<0j$jzCBdtm3fka(NAvj_GxF%mkTW%qD@Ar#(I5_T*d!r^hn|0swi0!qnJ6 zjL%hSX!DHqM`GbIN&oxlzKk!E%G`QEH;F!w`1qeNI-^ATONIP*e%I8{&h^)gY#cs) z+K#5T(~-TMU$h~1M_ByhMoIo>ZG~2CZ-Sv<&2#mHzh4sINN|_bR8@mx)Imz3al5z; zDj|xCzdSy4i zrL5!hpiV$7fZ*eYff*-q$pZ*fppwc_qg^Qb;G~WyNcDLF>B$KSrFqv7Z^o-IWeh5W zA(ofl5}?Vy`Eu+28kI_Idd*XnrC87vr*HGkn|}uzSST7{iZV~;EMk*RsF!Y(k>r*A z_efLUjrVpQb2-hz@^n5F6Yw#b6`!4b2xhO*Cr#(CzuNmNesj|?Co^H$zv~7fm>32r z@O_b|Dpygr(e-U{3e8v`4(iUMX2j&N+3a}z&wL+`W!1%V27b#sU9TGKErK&KkAafv zMSPRSFH36&aX(!RINf>xMfC7d>scSM`&!6Dk5Ve5HWU*8_8U-wEVR~(>PGvEOo<7t z^=RK6?hdNNrEJTlwcGwq+I^zBzkQx*(7dbXz;jDr6E&A_k}M`Mn4}D2eiU5=?Eh}L zYhW>(YA@`tDss6y-s5e15S#_6AAoah)+`H&48gB)Jw@kFxa&Z9Z0e{m-;q_Dwh!OE z)_Q>;2nrkk&`_8Oiuzq3I3qqw0M)#Dp(Cdr5sybUIc!14aB)o}KB+njR9xPm@auH~Z5lv6a>hhsk@*ie}iCEVvkn zdbVse*zn3F0~nd8ah z=zy$tI6&FR`utWl~?|IIi(D$$aS9~GBjQ--VPH<))#4g|KtM0^aeHF-a-Z^(*X%knB9>v7{G zKj#PCca0Arm>ww|En?S}a5vkQ-c(ais~L~el-B>)sOa+N0tXg`fXsS8`UFCHLNFcu zdD|X;Y2jz(`jo*ncIrU>c4RvzU-*GQ&pBCIYMx1)&;xn5>M?AyCO_x?0)s+Lr|PBp zVeHkZ;Wj708^?|p(i_-OG2m%Zg8C<#lMZ!o8ZGW@m7|*c)y@tWrZ*Q4bN^C3l~w&h#mlRsE!r94 zN%|_Vf5zwN=ZtcmLuW*;UDP+<;oBvhB9CLgMECwIKFoe`@8$e@mZo%c zoTl`NJLvZ5qdaHKe?=W1|10YF$WaFi;**O5*Ui9W3>vY1TG_S221dzHInWki`gVhl zjNw0ux{l+)1j|&+`7$2LKE>c@)C=c#@*-ZFm|qe80Yg$ji7IV$m*3N4k3M)2g4x*Z ztI7hZxNG*W#P=WOSXmtn-l-RNgzRK8ar)*#hNbphY;{$@WX* zKR>J;H39J%+$+Sx@J<=w#;=At-W6-tQ0C?BYT@w8ix)|VOo08KTzC8NG(d3`*o8Ft z{(#0d;m{d*P4xjIEVhpmZ$t}r%9g`0$i5V1`_7vZ{5t)yQPZU?PD&wSk|xc1*9Kv3 zjwN`+m{xVXr7H9>GzV;-gM4N#*wyI}gwGrvcD;E4__DTKiqTjbrAN`gA4g;}j$7a$CaE zD=*<-W`3HMR=TJjgCCsE@|`lNTa-A z#N|4UzU3TLwacxw3&70*VdWVZ+oXmq)R;;en`(SILEjeRReTUc6!d*)Jk9Fq*{ri$ z;*%cT{RT<^dLSRyADS+zL4*$g2LEaOXBVRwep$APgI?W|p6$(<{eL!C*q|7eVTbQ> zAalXZy?K8Kvl=c7HaXkKZ-1Xz?}sY;)y@ahxH7XmtfgBEt5JNfp0GE&nzxWKwwf=` zOFt}?uJ*S;N;C?E66YBPo$SYjJ93R_py;(9(~pmNZM z31QX9y;DiWTndXJ4!m$X2_>{}ZmQ~5vof5%=cDpX8ORgG#KibmB%c}xT<_?AF1jw* zp5L*CbS!G3Yyu<+0k~27YhV5YwnpbB)wliIx6K1@kmLMek(C|Xawb3iXhUjzE{-CO z0hPzS*&-mWK!eqrYyvqQJb^wyu-#)<&HNUH(4#h?ida4^{6#M(HZN6pC5hZhY=oac z4BE%(fDS{~R5|BZ^tU0Y|5ik`Wke}>keob9QQ$rocw}1wohcA$GW=X}=s_m{!D5tD z7kF%&Tw-0OWx*-uP#Yjj%JkXw!rPgUl+RmrDC5_{{*3|R z5G?F`GmbUlfVzg|&R#YuZ$`ahb*qsNO(4GhqQNWGvSVy-$j;OG-Jka?zwIL#W0W@D zQ$5^as(W)v@K#z<3NgLhIAGezOZ60E`8$2y!*Mnh(%OL>^6H?Ou|1Ah>z?adl)9Uz zf__Z3j_G>4F_@ZSP8Kyc0F9kaR%zvFkLR`Hbyd9Sn3karZkg7OVk#Gqdo}iNAGe<+ z!^w0u!O=DH&s^6n(!eeH{e6Ti0_ne-z`wt0C;{Mt$QKPl81l_Qrm}a1IpP?dOai~7 z?d`tCecDD;&ED|BXD17srR)m6ms-izh4`=PH>h6LSPTThqi(`;_R^b-+fj5!A+{aI z%pma~-#;GD)k;5=ik9xlJY3g1O9xGe{F_SdT+~~@(sg$ zX0IU`aySdppZXSLUXXLJpXC+bwDD<^M36H3wX3=5p6$Qdq4rn}7!?(NPTOx)3ndJY zfkCt`X

n=>krMYh+QY|x;U8R# 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

    rzWBHEevtv*Y_5nt#163>f=?NWwH!(dfq|hN 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 Int{ + let polygon = points.count + var orientation = 0 + + for i in 0.. 0 : CounterClockWise + } +} +``` + +Put this code in a playground and test it like so: + +```swift +var p1 = Point(x: 5, y: 8) +var p2 = Point(x: 9, y: 1) +var p3 = Point(x: 3, y: 6) + +print(ccw(points: [p1,p2,p3])) // -1 means ClockWise +``` + +Here's how it works. When given an `[Photo]`, `ccw(points:)` calculates the direction of the given points according to the Shoelaces formula. + + + +`orientation` is less than 0, the direction is clockwise. + +`orientation` is equal to 0, the direction is parallel. + +`orientation` is greater than 0, the direction is counterclockwise. + + + +## An example + +**In Triangle** + +```swift +var p1 = Point(x: 5, y: 8) +var p2 = Point(x: 9, y: 1) +var p3 = Point(x: 3, y: 6) + +print(ccw(points: [p1,p2,p3])) // -1 means ClockWise +``` + +![triangle](/Users/taejoongyoon/Developer/Swift/swift-algorithm-club/CounterClockWise/Images/Triangle_img.jpg) + +![triangleExpression](/Users/taejoongyoon/Developer/Swift/swift-algorithm-club/CounterClockWise/Images/triangle.png) + + + +**In Quadrilateral** + +```swift +var p4 = Point(x: 5, y: 8) +var p5 = Point(x: 2, y: 3) +var p6 = Point(x: 6, y: 1) +var p7 = Point(x: 9, y: 3) + +print(ccw(points: [p4,p5,p6,p7])) // 1 means CounterClockWise +``` + +![Quadrilateral](/Users/taejoongyoon/Developer/Swift/swift-algorithm-club/CounterClockWise/Images/Quadrilateral_img.jpg) + +![triangleExpression](/Users/taejoongyoon/Developer/Swift/swift-algorithm-club/CounterClockWise/Images/quadrilateral.png) + + + +**In Pentagon** + +```swift +var p8 = Point(x: 5, y: 11) +var p9 = Point(x: 3, y: 4) +var p10 = Point(x: 5, y: 6) +var p11 = Point(x: 9, y: 5) +var p12 = Point(x: 12, y: 8) + +print(ccw(points: [p8,p9,p10,p11,p12])) // 1 means CounterClockWise +``` + +![triangle](/Users/taejoongyoon/Developer/Swift/swift-algorithm-club/CounterClockWise/Images/Pentagon_img.png) + +![triangleExpression](/Users/taejoongyoon/Developer/Swift/swift-algorithm-club/CounterClockWise/Images/pentagon.png) + + + +You probably won't need to use the CCW in any real-world problems, but it's cool to play around with geometry algorithm. The formula was described by Meister (1724-1788) in 1769 and by Gauss in 1795. It can be verified by dividing the polygon into triangles, and can be considered to be a special case of Green's theorem. + + + +*Written for Swift Algorithm Club by TaeJoong Yoon* \ No newline at end of file diff --git a/README.markdown b/README.markdown index 90b310752..efe89edc0 100644 --- a/README.markdown +++ b/README.markdown @@ -109,6 +109,7 @@ Bad sorting algorithms (don't use these!): - [Karatsuba Multiplication](Karatsuba%20Multiplication/). Another take on elementary multiplication. - [Haversine Distance](HaversineDistance/). Calculating the distance between 2 points from a sphere. - [Strassen's Multiplication Matrix](Strassen%20Matrix%20Multiplication/). Efficient way to handle matrix multiplication. +- [CounterClockWise](/CounterClockWise/). Determining the area of a simple polygon. ### Machine learning From e48117cd2cd5efaec539eb83c44d47089edc5054 Mon Sep 17 00:00:00 2001 From: TaeJoong Yoon Date: Wed, 17 Oct 2018 04:22:34 +0900 Subject: [PATCH 104/271] Update README.md --- CounterClockWise/README.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/CounterClockWise/README.md b/CounterClockWise/README.md index 6b6c1a1da..2d15eba53 100644 --- a/CounterClockWise/README.md +++ b/CounterClockWise/README.md @@ -70,9 +70,9 @@ var p3 = Point(x: 3, y: 6) print(ccw(points: [p1,p2,p3])) // -1 means ClockWise ``` -![triangle](/Users/taejoongyoon/Developer/Swift/swift-algorithm-club/CounterClockWise/Images/Triangle_img.jpg) +![triangle](./Images/Triangle_img.jpg) -![triangleExpression](/Users/taejoongyoon/Developer/Swift/swift-algorithm-club/CounterClockWise/Images/triangle.png) +![triangleExpression](./Images/triangle.png) @@ -87,9 +87,9 @@ var p7 = Point(x: 9, y: 3) print(ccw(points: [p4,p5,p6,p7])) // 1 means CounterClockWise ``` -![Quadrilateral](/Users/taejoongyoon/Developer/Swift/swift-algorithm-club/CounterClockWise/Images/Quadrilateral_img.jpg) +![Quadrilateral](./Images/Quadrilateral_img.jpg) -![triangleExpression](/Users/taejoongyoon/Developer/Swift/swift-algorithm-club/CounterClockWise/Images/quadrilateral.png) +![triangleExpression](./Images/quadrilateral.png) @@ -105,9 +105,9 @@ var p12 = Point(x: 12, y: 8) print(ccw(points: [p8,p9,p10,p11,p12])) // 1 means CounterClockWise ``` -![triangle](/Users/taejoongyoon/Developer/Swift/swift-algorithm-club/CounterClockWise/Images/Pentagon_img.png) +![triangle](./Images/Pentagon_img.png) -![triangleExpression](/Users/taejoongyoon/Developer/Swift/swift-algorithm-club/CounterClockWise/Images/pentagon.png) +![triangleExpression](./Images/pentagon.png) @@ -115,4 +115,4 @@ You probably won't need to use the CCW in any real-world problems, but it's cool -*Written for Swift Algorithm Club by TaeJoong Yoon* \ No newline at end of file +*Written for Swift Algorithm Club by TaeJoong Yoon* From d321542c220e94607b056644c491c7436553103b Mon Sep 17 00:00:00 2001 From: Alex Persian Date: Tue, 16 Oct 2018 22:28:13 -0400 Subject: [PATCH 105/271] Changes class to enum and clarifies the reason why a copy is made --- Linked List/README.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Linked List/README.markdown b/Linked List/README.markdown index 0c8431157..e81e00b9f 100644 --- a/Linked List/README.markdown +++ b/Linked List/README.markdown @@ -555,7 +555,7 @@ enum ListNode { } ``` -The big difference with the class-based version is that any modification you make to this list will result in a *new copy* being created. Whether that's what you want or not depends on the application. +The big difference with the enum-based version is that any modification you make to this list will result in a *new copy* being created because of [Swift's value semantics](https://developer.apple.com/swift/blog/?id=10). Whether that's what you want or not depends on the application. [I might fill out this section in more detail if there's a demand for it.] From f95093e7338bc66d73ff81b52f959ec0f4fdd2b5 Mon Sep 17 00:00:00 2001 From: Michael Pchelnikov Date: Thu, 18 Oct 2018 00:28:16 +0300 Subject: [PATCH 106/271] Update Sorted Set to Swift 4.2 --- .../Pages/Example 1.xcplaygroundpage/Contents.swift | 5 ----- 1 file changed, 5 deletions(-) diff --git a/Sorted Set/SortedSet.playground/Pages/Example 1.xcplaygroundpage/Contents.swift b/Sorted Set/SortedSet.playground/Pages/Example 1.xcplaygroundpage/Contents.swift index 45af5f99d..c81f4d915 100644 --- a/Sorted Set/SortedSet.playground/Pages/Example 1.xcplaygroundpage/Contents.swift +++ b/Sorted Set/SortedSet.playground/Pages/Example 1.xcplaygroundpage/Contents.swift @@ -1,8 +1,3 @@ -// last checked with Xcode 9.0b4 -#if swift(>=4.0) -print("Hello, Swift 4!") -#endif - //: # Example 1 with type Int var mySet = SortedSet() From 0c93543179946a42b44a11fb79061a6126a8d8b5 Mon Sep 17 00:00:00 2001 From: Erik Strottmann Date: Wed, 17 Oct 2018 22:01:48 -0700 Subject: [PATCH 107/271] Update Trie to Swift 4.2 Removes `#if swift(>=4.0)` checks and calls to deprecated `String.characters` property, and enables Xcode 10 recommended warnings. --- Trie/ReadMe.md | 4 +-- Trie/Trie/Trie.xcodeproj/project.pbxproj | 33 +++++++++++++++---- .../xcshareddata/IDEWorkspaceChecks.plist | 8 +++++ Trie/Trie/Trie/Trie.swift | 11 ++----- Trie/Trie/Trie/ViewController.swift | 5 --- Trie/Trie/TrieTests/TrieTests.swift | 5 --- 6 files changed, 39 insertions(+), 27 deletions(-) create mode 100644 Trie/Trie/Trie.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist diff --git a/Trie/ReadMe.md b/Trie/ReadMe.md index 34b9beb9c..8e473a619 100644 --- a/Trie/ReadMe.md +++ b/Trie/ReadMe.md @@ -33,7 +33,7 @@ func contains(word: String) -> Bool { var currentNode = root // 2 - var characters = Array(word.lowercased().characters) + var characters = Array(word.lowercased()) var currentIndex = 0 // 3 @@ -74,7 +74,7 @@ func insert(word: String) { var currentNode = root // 2 - for character in word.lowercased().characters { + for character in word.lowercased() { // 3 if let childNode = currentNode.children[character] { currentNode = childNode diff --git a/Trie/Trie/Trie.xcodeproj/project.pbxproj b/Trie/Trie/Trie.xcodeproj/project.pbxproj index 90c5734cc..1e3602eea 100644 --- a/Trie/Trie/Trie.xcodeproj/project.pbxproj +++ b/Trie/Trie/Trie.xcodeproj/project.pbxproj @@ -195,20 +195,23 @@ isa = PBXProject; attributes = { LastSwiftUpdateCheck = 0810; - LastUpgradeCheck = 0820; + LastUpgradeCheck = 1000; ORGANIZATIONNAME = "Rick Zaccone"; TargetAttributes = { EB798DF91DFEF79900F0628D = { CreatedOnToolsVersion = 8.1; + LastSwiftMigration = 1000; ProvisioningStyle = Automatic; }; EB798E0A1DFEF79900F0628D = { CreatedOnToolsVersion = 8.1; + LastSwiftMigration = 1000; ProvisioningStyle = Automatic; TestTargetID = EB798DF91DFEF79900F0628D; }; EB798E151DFEF79900F0628D = { CreatedOnToolsVersion = 8.1; + LastSwiftMigration = 1000; ProvisioningStyle = Automatic; TestTargetID = EB798DF91DFEF79900F0628D; }; @@ -326,15 +329,23 @@ CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_DOCUMENTATION_COMMENTS = YES; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_SUSPICIOUS_MOVES = YES; CLANG_WARN_UNREACHABLE_CODE = YES; @@ -376,15 +387,23 @@ CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_DOCUMENTATION_COMMENTS = YES; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_SUSPICIOUS_MOVES = YES; CLANG_WARN_UNREACHABLE_CODE = YES; @@ -418,7 +437,7 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = edu.bucknell.zaccone.Trie; PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 3.0; + SWIFT_VERSION = 4.2; }; name = Debug; }; @@ -431,7 +450,7 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = edu.bucknell.zaccone.Trie; PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 3.0; + SWIFT_VERSION = 4.2; }; name = Release; }; @@ -445,7 +464,7 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = edu.bucknell.zaccone.TrieTests; PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 3.0; + SWIFT_VERSION = 4.2; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Trie.app/Contents/MacOS/Trie"; }; name = Debug; @@ -460,7 +479,7 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = edu.bucknell.zaccone.TrieTests; PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 3.0; + SWIFT_VERSION = 4.2; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Trie.app/Contents/MacOS/Trie"; }; name = Release; @@ -474,7 +493,7 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = edu.bucknell.zaccone.TrieUITests; PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 3.0; + SWIFT_VERSION = 4.2; TEST_TARGET_NAME = Trie; }; name = Debug; @@ -488,7 +507,7 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = edu.bucknell.zaccone.TrieUITests; PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 3.0; + SWIFT_VERSION = 4.2; TEST_TARGET_NAME = Trie; }; name = Release; diff --git a/Trie/Trie/Trie.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Trie/Trie/Trie.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/Trie/Trie/Trie.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/Trie/Trie/Trie/Trie.swift b/Trie/Trie/Trie/Trie.swift index 1a7017c4c..fbc933138 100644 --- a/Trie/Trie/Trie/Trie.swift +++ b/Trie/Trie/Trie/Trie.swift @@ -6,11 +6,6 @@ // Copyright © 2016 Rick Zaccone. All rights reserved. // -// last checked with Xcode 9.0b4 -#if swift(>=4.0) - print("Hello, Swift 4!") -#endif - import Foundation /// A node in the trie @@ -105,7 +100,7 @@ extension Trie { return } var currentNode = root - for character in word.lowercased().characters { + for character in word.lowercased() { if let childNode = currentNode.children[character] { currentNode = childNode } else { @@ -130,7 +125,7 @@ extension Trie { return false } var currentNode = root - for character in word.lowercased().characters { + for character in word.lowercased() { guard let childNode = currentNode.children[character] else { return false } @@ -148,7 +143,7 @@ extension Trie { /// search failed. private func findLastNodeOf(word: String) -> Node? { var currentNode = root - for character in word.lowercased().characters { + for character in word.lowercased() { guard let childNode = currentNode.children[character] else { return nil } diff --git a/Trie/Trie/Trie/ViewController.swift b/Trie/Trie/Trie/ViewController.swift index 9c5e66163..928b01f4c 100644 --- a/Trie/Trie/Trie/ViewController.swift +++ b/Trie/Trie/Trie/ViewController.swift @@ -6,11 +6,6 @@ // Copyright © 2016 Rick Zaccone. All rights reserved. // -// last checked with Xcode 9.0b4 -#if swift(>=4.0) - print("Hello, Swift 4!") -#endif - import Cocoa class ViewController: NSViewController { diff --git a/Trie/Trie/TrieTests/TrieTests.swift b/Trie/Trie/TrieTests/TrieTests.swift index 45be03aad..b69c5666e 100644 --- a/Trie/Trie/TrieTests/TrieTests.swift +++ b/Trie/Trie/TrieTests/TrieTests.swift @@ -6,11 +6,6 @@ // Copyright © 2016 Rick Zaccone. All rights reserved. // -// last checked with Xcode 9.0b4 -#if swift(>=4.0) - print("Hello, Swift 4!") -#endif - import XCTest @testable import Trie From 5a200e0709ba32a7bd898336502264977b356f77 Mon Sep 17 00:00:00 2001 From: Florian Heiber Date: Thu, 18 Oct 2018 09:25:37 +0200 Subject: [PATCH 108/271] renaming Palindromes to Palindrome also removing one implementation, moving the one on root level to the playground to reduce the number of implementations to maintain --- .../Sources/Palindrome.swift | 38 +++++++++++++++++++ .../xcshareddata/IDEWorkspaceChecks.plist | 8 ++++ .../Palindrome.swift} | 2 +- Palindromes/Test/Palindromes.swift | 26 ------------- .../Test/Test.xcodeproj/project.pbxproj | 16 +++++--- .../xcshareddata/IDEWorkspaceChecks.plist | 8 ++++ 6 files changed, 65 insertions(+), 33 deletions(-) create mode 100644 Palindromes/Palindromes.playground/Sources/Palindrome.swift create mode 100644 Palindromes/Palindromes.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist rename Palindromes/{Palindromes.swift => Test/Palindrome.swift} (93%) delete mode 100644 Palindromes/Test/Palindromes.swift create mode 100644 Palindromes/Test/Test.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist diff --git a/Palindromes/Palindromes.playground/Sources/Palindrome.swift b/Palindromes/Palindromes.playground/Sources/Palindrome.swift new file mode 100644 index 000000000..a6d2274bf --- /dev/null +++ b/Palindromes/Palindromes.playground/Sources/Palindrome.swift @@ -0,0 +1,38 @@ +import Foundation + +/** + Validate that a string is a plaindrome + - parameter str: The string to validate + - returns: `true` if string is plaindrome, `false` if string is not + */ +func isPalindrome(_ str: String) -> Bool { + let strippedString = str.replacingOccurrences(of: "\\W", with: "", options: .regularExpression, range: nil) + let length = strippedString.count + + if length > 1 { + return palindrome(strippedString.lowercased(), left: 0, right: length - 1) + } + return false +} + +/** + Compares a strings left side character against right side character following + - parameter str: The string to compare characters of + - parameter left: Index of left side to compare, must be less than or equal to right + - parameter right: Index of right side to compare, must be greater than or equal to left + - returns: `true` if left side and right side have all been compared and they all match, `false` if a left and right aren't equal + */ +private func palindrome(_ str: String, left: Int, right: Int) -> Bool { + if left >= right { + return true + } + + let lhs = str[str.index(str.startIndex, offsetBy: left)] + let rhs = str[str.index(str.startIndex, offsetBy: right)] + + if lhs != rhs { + return false + } + + return palindrome(str, left: left + 1, right: right - 1) +} diff --git a/Palindromes/Palindromes.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Palindromes/Palindromes.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/Palindromes/Palindromes.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/Palindromes/Palindromes.swift b/Palindromes/Test/Palindrome.swift similarity index 93% rename from Palindromes/Palindromes.swift rename to Palindromes/Test/Palindrome.swift index 9ddd04c80..16af14fdb 100644 --- a/Palindromes/Palindromes.swift +++ b/Palindromes/Test/Palindrome.swift @@ -2,7 +2,7 @@ import Foundation func isPalindrome(_ str: String) -> Bool { let strippedString = str.replacingOccurrences(of: "\\W", with: "", options: .regularExpression, range: nil) - let length = strippedString.characters.count + let length = strippedString.count if length > 1 { return palindrome(strippedString.lowercased(), left: 0, right: length - 1) diff --git a/Palindromes/Test/Palindromes.swift b/Palindromes/Test/Palindromes.swift deleted file mode 100644 index 9ddd04c80..000000000 --- a/Palindromes/Test/Palindromes.swift +++ /dev/null @@ -1,26 +0,0 @@ -import Foundation - -func isPalindrome(_ str: String) -> Bool { - let strippedString = str.replacingOccurrences(of: "\\W", with: "", options: .regularExpression, range: nil) - let length = strippedString.characters.count - - if length > 1 { - return palindrome(strippedString.lowercased(), left: 0, right: length - 1) - } - return false -} - -private func palindrome(_ str: String, left: Int, right: Int) -> Bool { - if left >= right { - return true - } - - let lhs = str[str.index(str.startIndex, offsetBy: left)] - let rhs = str[str.index(str.startIndex, offsetBy: right)] - - if lhs != rhs { - return false - } - - return palindrome(str, left: left + 1, right: right - 1) -} diff --git a/Palindromes/Test/Test.xcodeproj/project.pbxproj b/Palindromes/Test/Test.xcodeproj/project.pbxproj index 07aae3e63..6af90d5c2 100644 --- a/Palindromes/Test/Test.xcodeproj/project.pbxproj +++ b/Palindromes/Test/Test.xcodeproj/project.pbxproj @@ -8,11 +8,11 @@ /* Begin PBXBuildFile section */ 9437D8841E0D960A00A38FB8 /* Test.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9437D8831E0D960A00A38FB8 /* Test.swift */; }; - 9437D88B1E0D969500A38FB8 /* Palindromes.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9437D8791E0D948A00A38FB8 /* Palindromes.swift */; }; + 9437D88B1E0D969500A38FB8 /* Palindrome.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9437D8791E0D948A00A38FB8 /* Palindrome.swift */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ - 9437D8791E0D948A00A38FB8 /* Palindromes.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Palindromes.swift; sourceTree = ""; }; + 9437D8791E0D948A00A38FB8 /* Palindrome.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Palindrome.swift; sourceTree = ""; }; 9437D8811E0D960A00A38FB8 /* Test.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = Test.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 9437D8831E0D960A00A38FB8 /* Test.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Test.swift; sourceTree = ""; }; 9437D8851E0D960A00A38FB8 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; @@ -32,7 +32,7 @@ 9437D8651E0D945200A38FB8 = { isa = PBXGroup; children = ( - 9437D8791E0D948A00A38FB8 /* Palindromes.swift */, + 9437D8791E0D948A00A38FB8 /* Palindrome.swift */, 9437D8821E0D960A00A38FB8 /* Test */, 9437D86F1E0D945200A38FB8 /* Products */, ); @@ -87,6 +87,7 @@ TargetAttributes = { 9437D8801E0D960A00A38FB8 = { CreatedOnToolsVersion = 8.2; + LastSwiftMigration = 1000; ProvisioningStyle = Automatic; }; }; @@ -123,7 +124,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 9437D88B1E0D969500A38FB8 /* Palindromes.swift in Sources */, + 9437D88B1E0D969500A38FB8 /* Palindrome.swift in Sources */, 9437D8841E0D960A00A38FB8 /* Test.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -229,7 +230,8 @@ PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 3.0; + SWIFT_SWIFT3_OBJC_INFERENCE = On; + SWIFT_VERSION = 4.2; }; name = Debug; }; @@ -243,7 +245,8 @@ PRODUCT_BUNDLE_IDENTIFIER = self.edu.Test; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; - SWIFT_VERSION = 3.0; + SWIFT_SWIFT3_OBJC_INFERENCE = On; + SWIFT_VERSION = 4.2; }; name = Release; }; @@ -266,6 +269,7 @@ 9437D8881E0D960A00A38FB8 /* Release */, ); defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; }; /* End XCConfigurationList section */ }; diff --git a/Palindromes/Test/Test.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Palindromes/Test/Test.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/Palindromes/Test/Test.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + From 73b0fc92b71fa5a40a8b6ddc6a664ede35d09858 Mon Sep 17 00:00:00 2001 From: Florian Heiber Date: Thu, 18 Oct 2018 09:26:50 +0200 Subject: [PATCH 109/271] removing duplicate implementation --- .../Palindromes.playground/Contents.swift | 42 ------------------- 1 file changed, 42 deletions(-) diff --git a/Palindromes/Palindromes.playground/Contents.swift b/Palindromes/Palindromes.playground/Contents.swift index 44662745a..ee43cce33 100644 --- a/Palindromes/Palindromes.playground/Contents.swift +++ b/Palindromes/Palindromes.playground/Contents.swift @@ -1,49 +1,7 @@ //: Playground - noun: a place where people can play -// last checked with Xcode 9.0b4 -#if swift(>=4.0) -print("Hello, Swift 4!") -#endif - import Foundation -/** - Validate that a string is a plaindrome - - parameter str: The string to validate - - returns: `true` if string is plaindrome, `false` if string is not - */ -func isPalindrome(_ str: String) -> Bool { - let strippedString = str.replacingOccurrences(of: "\\W", with: "", options: .regularExpression, range: nil) - let length = strippedString.characters.count - - if length > 1 { - return palindrome(strippedString.lowercased(), left: 0, right: length - 1) - } - return false -} - -/** - Compares a strings left side character against right side character following - - parameter str: The string to compare characters of - - parameter left: Index of left side to compare, must be less than or equal to right - - parameter right: Index of right side to compare, must be greater than or equal to left - - returns: `true` if left side and right side have all been compared and they all match, `false` if a left and right aren't equal - */ -private func palindrome(_ str: String, left: Int, right: Int) -> Bool { - if left >= right { - return true - } - - let lhs = str[str.index(str.startIndex, offsetBy: left)] - let rhs = str[str.index(str.startIndex, offsetBy: right)] - - if lhs != rhs { - return false - } - - return palindrome(str, left: left + 1, right: right - 1) -} - //true isPalindrome("A man, a plan, a canal, Panama!") isPalindrome("abbcbba") From 66509650d57cd11deeb081359cbc0e4f68877b8e Mon Sep 17 00:00:00 2001 From: Florian Heiber Date: Thu, 18 Oct 2018 09:27:09 +0200 Subject: [PATCH 110/271] updating recommended project settings --- .../Test/Test.xcodeproj/project.pbxproj | 18 +++++++++++++++++- .../xcshareddata/xcschemes/Test.xcscheme | 2 +- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/Palindromes/Test/Test.xcodeproj/project.pbxproj b/Palindromes/Test/Test.xcodeproj/project.pbxproj index 6af90d5c2..8125d1f8d 100644 --- a/Palindromes/Test/Test.xcodeproj/project.pbxproj +++ b/Palindromes/Test/Test.xcodeproj/project.pbxproj @@ -82,7 +82,7 @@ isa = PBXProject; attributes = { LastSwiftUpdateCheck = 0820; - LastUpgradeCheck = 0820; + LastUpgradeCheck = 1000; ORGANIZATIONNAME = "Joshua Alvarado"; TargetAttributes = { 9437D8801E0D960A00A38FB8 = { @@ -141,15 +141,23 @@ CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_DOCUMENTATION_COMMENTS = YES; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; @@ -188,15 +196,23 @@ CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_DOCUMENTATION_COMMENTS = YES; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; diff --git a/Palindromes/Test/Test.xcodeproj/xcshareddata/xcschemes/Test.xcscheme b/Palindromes/Test/Test.xcodeproj/xcshareddata/xcschemes/Test.xcscheme index 9a1b39e69..72ae3d696 100644 --- a/Palindromes/Test/Test.xcodeproj/xcshareddata/xcschemes/Test.xcscheme +++ b/Palindromes/Test/Test.xcodeproj/xcshareddata/xcschemes/Test.xcscheme @@ -1,6 +1,6 @@ Date: Thu, 18 Oct 2018 09:28:36 +0200 Subject: [PATCH 111/271] setting SWIFT_SWIFT3_OBJC_INFERENCE to default --- Palindromes/Test/Test.xcodeproj/project.pbxproj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Palindromes/Test/Test.xcodeproj/project.pbxproj b/Palindromes/Test/Test.xcodeproj/project.pbxproj index 8125d1f8d..f01f6f061 100644 --- a/Palindromes/Test/Test.xcodeproj/project.pbxproj +++ b/Palindromes/Test/Test.xcodeproj/project.pbxproj @@ -246,7 +246,7 @@ PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_SWIFT3_OBJC_INFERENCE = On; + SWIFT_SWIFT3_OBJC_INFERENCE = Default; SWIFT_VERSION = 4.2; }; name = Debug; @@ -261,7 +261,7 @@ PRODUCT_BUNDLE_IDENTIFIER = self.edu.Test; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; - SWIFT_SWIFT3_OBJC_INFERENCE = On; + SWIFT_SWIFT3_OBJC_INFERENCE = Default; SWIFT_VERSION = 4.2; }; name = Release; From d3acedfb063b65327d503a50e86dfbaeb545b90e Mon Sep 17 00:00:00 2001 From: Florian Heiber Date: Thu, 18 Oct 2018 09:31:39 +0200 Subject: [PATCH 112/271] making isPalindrome(_:) public --- Palindromes/Palindromes.playground/Sources/Palindrome.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Palindromes/Palindromes.playground/Sources/Palindrome.swift b/Palindromes/Palindromes.playground/Sources/Palindrome.swift index a6d2274bf..3652dbb1f 100644 --- a/Palindromes/Palindromes.playground/Sources/Palindrome.swift +++ b/Palindromes/Palindromes.playground/Sources/Palindrome.swift @@ -5,7 +5,7 @@ import Foundation - parameter str: The string to validate - returns: `true` if string is plaindrome, `false` if string is not */ -func isPalindrome(_ str: String) -> Bool { +public func isPalindrome(_ str: String) -> Bool { let strippedString = str.replacingOccurrences(of: "\\W", with: "", options: .regularExpression, range: nil) let length = strippedString.count From 5fe31fff9a5717815cb524b16eb3433fde20926b Mon Sep 17 00:00:00 2001 From: Florian Heiber Date: Thu, 18 Oct 2018 09:31:42 +0200 Subject: [PATCH 113/271] cleanup --- Palindromes/Palindromes.playground/Contents.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Palindromes/Palindromes.playground/Contents.swift b/Palindromes/Palindromes.playground/Contents.swift index ee43cce33..49f767982 100644 --- a/Palindromes/Palindromes.playground/Contents.swift +++ b/Palindromes/Palindromes.playground/Contents.swift @@ -2,7 +2,7 @@ import Foundation -//true +// true isPalindrome("A man, a plan, a canal, Panama!") isPalindrome("abbcbba") isPalindrome("racecar") From 93a4d2d24689ebc6beec1df55e28dc4e94318a96 Mon Sep 17 00:00:00 2001 From: Florian Heiber Date: Thu, 18 Oct 2018 09:55:39 +0200 Subject: [PATCH 114/271] updating README --- Palindromes/README.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Palindromes/README.markdown b/Palindromes/README.markdown index 69520a132..e4012d8da 100644 --- a/Palindromes/README.markdown +++ b/Palindromes/README.markdown @@ -26,7 +26,7 @@ Here is a recursive implementation of this in Swift: ```swift func isPalindrome(_ str: String) -> Bool { let strippedString = str.replacingOccurrences(of: "\\W", with: "", options: .regularExpression, range: nil) - let length = strippedString.characters.count + let length = strippedString.count if length > 1 { return palindrome(strippedString.lowercased(), left: 0, right: length - 1) From c4a89a24bee0269733f2ac8ed9605ae0f1574eaa Mon Sep 17 00:00:00 2001 From: Stefan Pleava Date: Thu, 18 Oct 2018 11:45:46 -0400 Subject: [PATCH 115/271] Update README.markdown I think it should say minimum not maximum in the description. --- Egg Drop Problem/README.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Egg Drop Problem/README.markdown b/Egg Drop Problem/README.markdown index b2f45d09e..416984193 100644 --- a/Egg Drop Problem/README.markdown +++ b/Egg Drop Problem/README.markdown @@ -12,7 +12,7 @@ If the object is incredibly resilient, and you may need to do the testing on the ## Description -You're in a building with **m** floors and you are given **n** eggs. What is the maximum number of attempts it will take to find out the floor that breaks the egg? +You're in a building with **m** floors and you are given **n** eggs. What is the minimum number of attempts it will take to find out the floor that breaks the egg? For convenience, here are a few rules to keep in mind: From 4c718b4023565795675de2b2755db3226b3cd55e Mon Sep 17 00:00:00 2001 From: vp4 Date: Fri, 19 Oct 2018 18:24:40 +0530 Subject: [PATCH 116/271] Remove semicolon --- Linked List/README.markdown | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Linked List/README.markdown b/Linked List/README.markdown index 0998349fc..d6f1fc986 100644 --- a/Linked List/README.markdown +++ b/Linked List/README.markdown @@ -490,9 +490,9 @@ Recursive Approach: return head } let temp = reverse(head.next) - head.next.next = head; - head.next = NULL; - return temp; + head.next.next = head + head.next = NULL + return temp } ``` From 66d0b867e22378465d83aecce1c30609906538d5 Mon Sep 17 00:00:00 2001 From: Randy the Dev <37282011+RandyTheDev@users.noreply.github.com> Date: Mon, 22 Oct 2018 03:05:09 +1100 Subject: [PATCH 117/271] Updated Radix Sort to Swift 4.2 --- Radix Sort/RadixSort.playground/Contents.swift | 15 ++------------- .../RadixSort.playground/Sources/radixSort.swift | 1 - 2 files changed, 2 insertions(+), 14 deletions(-) diff --git a/Radix Sort/RadixSort.playground/Contents.swift b/Radix Sort/RadixSort.playground/Contents.swift index 941723c37..0b549fc9e 100644 --- a/Radix Sort/RadixSort.playground/Contents.swift +++ b/Radix Sort/RadixSort.playground/Contents.swift @@ -1,21 +1,10 @@ //: Playground - noun: a place where people can play -import Cocoa - -// last checked with Xcode 9.0b4 -#if swift(>=4.0) -print("Hello, Swift 4!") -#endif - // Test Radix Sort with small array of ten values var array: [Int] = [19, 4242, 2, 9, 912, 101, 55, 67, 89, 32] radixSort(&array) // Test Radix Sort with large array of 1000 random values -var bigArray = [Int](repeating: 0, count: 1000) -var i = 0 -while i < 1000 { - bigArray[i] = Int(arc4random_uniform(1000) + 1) - i += 1 -} +var bigArray = (0..<1000).map { _ in Int.random(in: 1...1000) } +bigArray radixSort(&bigArray) diff --git a/Radix Sort/RadixSort.playground/Sources/radixSort.swift b/Radix Sort/RadixSort.playground/Sources/radixSort.swift index 424d33fb9..af382f481 100644 --- a/Radix Sort/RadixSort.playground/Sources/radixSort.swift +++ b/Radix Sort/RadixSort.playground/Sources/radixSort.swift @@ -3,7 +3,6 @@ Sorting Algorithm that sorts an input array of integers digit by digit. */ -import Foundation // NOTE: This implementation does not handle negative numbers public func radixSort(_ array: inout [Int] ) { From 36ae366ea4faeb4bf96380df3d58ca4da34525c6 Mon Sep 17 00:00:00 2001 From: Randy the Dev <37282011+RandyTheDev@users.noreply.github.com> Date: Mon, 22 Oct 2018 04:01:21 +1100 Subject: [PATCH 118/271] Updated Radix Sort Tests to Swift 4.2 --- Radix Sort/Tests/RadixSortTests.swift | 7 ------- 1 file changed, 7 deletions(-) diff --git a/Radix Sort/Tests/RadixSortTests.swift b/Radix Sort/Tests/RadixSortTests.swift index 9b881318a..688bcdcb8 100644 --- a/Radix Sort/Tests/RadixSortTests.swift +++ b/Radix Sort/Tests/RadixSortTests.swift @@ -9,13 +9,6 @@ import XCTest class RadixSortTests: XCTestCase { - func testSwift4() { - // last checked with Xcode 9.0b4 - #if swift(>=4.0) - print("Hello, Swift 4!") - #endif - } - func testCombSort() { let expectedSequence: [Int] = [2, 9, 19, 32, 55, 67, 89, 101, 912, 4242] var sequence = [19, 4242, 2, 9, 912, 101, 55, 67, 89, 32] From eab858255456bc4c3be0229cf852d91720ac3361 Mon Sep 17 00:00:00 2001 From: Rahul Sharma Date: Tue, 23 Oct 2018 18:08:08 +0530 Subject: [PATCH 119/271] [Swift 4.2] Updated Linear Search The code worked fine in Xcode 10. I removed code snippet at the top of playground file. --- Linear Search/LinearSearch.playground/Contents.swift | 5 ----- 1 file changed, 5 deletions(-) diff --git a/Linear Search/LinearSearch.playground/Contents.swift b/Linear Search/LinearSearch.playground/Contents.swift index 8ac0e9a71..8c616ded4 100644 --- a/Linear Search/LinearSearch.playground/Contents.swift +++ b/Linear Search/LinearSearch.playground/Contents.swift @@ -1,10 +1,5 @@ //: Playground - noun: a place where people can play -// last checked with Xcode 9.0b4 -#if swift(>=4.0) -print("Hello, Swift 4!") -#endif - func linearSearch(_ array: [T], _ object: T) -> Int? { for (index, obj) in array.enumerated() where obj == object { return index From d4fdc7bfa84715fcae452439e874740fc6759d7f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20C=2E=20Kr=C3=BCger?= Date: Tue, 23 Oct 2018 15:32:33 +0200 Subject: [PATCH 120/271] Adds binary recursive stein algorithm to the GCD class * Improves the LCM by passing the used GCD algorithm into the function. * Find an easy GCD function if possible. --- GCD/GCD.playground/Contents.swift | 165 +++++++++++++++--- .../xcshareddata/IDEWorkspaceChecks.plist | 8 + GCD/GCD.playground/timeline.xctimeline | 6 - GCD/GCD.swift | 141 ++++++++++++--- GCD/README.markdown | 68 ++++---- 5 files changed, 296 insertions(+), 92 deletions(-) create mode 100644 GCD/GCD.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist delete mode 100644 GCD/GCD.playground/timeline.xctimeline diff --git a/GCD/GCD.playground/Contents.swift b/GCD/GCD.playground/Contents.swift index c44f28310..9dfd7cca9 100644 --- a/GCD/GCD.playground/Contents.swift +++ b/GCD/GCD.playground/Contents.swift @@ -1,39 +1,148 @@ //: Playground - noun: a place where people can play -// Recursive version -func gcd(_ a: Int, _ b: Int) -> Int { - let r = a % b - if r != 0 { - return gcd(b, r) - } else { +/* + Iterative approach based on the Euclidean algorithm. + The Euclidean algorithm is based on the principle that the greatest + common divisor of two numbers does not change if the larger number + is replaced by its difference with the smaller number. + - Parameter m: First natural number + - Parameter n: Second natural number + - Returns: The natural gcd if m and n + */ +func gcdIterativeEuklid(_ m: Int, _ n: Int) -> Int { + var a: Int = 0 + var b: Int = max(m, n) + var r: Int = min(m, n) + + while r != 0 { + a = b + b = r + r = a % b + } return b - } } /* -// Iterative version -func gcd(m: Int, _ n: Int) -> Int { - var a = 0 - var b = max(m, n) - var r = min(m, n) - - while r != 0 { - a = b - b = r - r = a % b - } - return b + Recursive approach based on the Euclidean algorithm. + + - Parameter m: First natural number + - Parameter n: Second natural number + - Returns: The natural gcd of m and n + - Note: The recursive version makes only tail recursive calls. + Most compilers for imperative languages do not optimize these. + The swift compiler as well as the obj-c compiler is able to do + optimizations for tail recursive calls, even though it still ends + up to be the same in terms of complexity. That said, tail call + elimination is not mutually exclusive to recursion. + */ +func gcdRecursiveEuklid(_ m: Int, _ n: Int) -> Int { + let r: Int = m % n + if r != 0 { + return gcdRecursiveEuklid(n, r) + } else { + return n + } +} + +/* + The binary GCD algorithm, also known as Stein's algorithm, + is an algorithm that computes the greatest common divisor of two + nonnegative integers. Stein's algorithm uses simpler arithmetic + operations than the conventional Euclidean algorithm; it replaces + division with arithmetic shifts, comparisons, and subtraction. + + - Parameter m: First natural number + - Parameter n: Second natural number + - Returns: The natural gcd of m and n + - Complexity: worst case O(n^2), where n is the number of bits + in the larger of the two numbers. Although each step reduces + at least one of the operands by at least a factor of 2, + the subtract and shift operations take linear time for very + large integers + */ +func gcdBinaryRecursiveStein(_ m: Int, _ n: Int) -> Int { + if let easySolution = findEasySolution(m, n) { return easySolution } + + if (m & 1) == 0 { + // m is even + if (n & 1) == 1 { + // and n is odd + return gcdBinaryRecursiveStein(m >> 1, n) + } else { + // both m and n are even + return gcdBinaryRecursiveStein(m >> 1, n >> 1) << 1 + } + } else if (n & 1) == 0 { + // m is odd, n is even + return gcdBinaryRecursiveStein(m, n >> 1) + } else if (m > n) { + // reduce larger argument + return gcdBinaryRecursiveStein((m - n) >> 1, n) + } else { + // reduce larger argument + return gcdBinaryRecursiveStein((n - m) >> 1, m) + } +} + +/* + Finds an easy solution for the gcd. + - Note: It might be relevant for different usecases to + try finding an easy solution for the GCD calculation + before even starting more difficult operations. + */ +func findEasySolution(_ m: Int, _ n: Int) -> Int? { + if m == n { + return m + } + if m == 0 { + return n + } + if n == 0 { + return m + } + return nil } -*/ -func lcm(_ m: Int, _ n: Int) -> Int { - return m / gcd(m, n) * n // we divide before multiplying to avoid integer overflow + +enum LCMError: Error { + case divisionByZero + case lcmEmptyList +} + +/* + Calculates the lcm for two given numbers using a specified gcd algorithm. + + - Parameter m: First natural number. + - Parameter n: Second natural number. + - Parameter using: The used gcd algorithm to calculate the lcm. + - Throws: Can throw a `divisionByZero` error if one of the given + attributes turns out to be zero or less. + - Returns: The least common multiplier of the two attributes as + an unsigned integer + */ +func lcm(_ m: Int, _ n: Int, using gcdAlgorithm: (Int, Int) -> (Int)) throws -> Int { + guard (m & n) != 0 else { throw LCMError.divisionByZero } + return m / gcdAlgorithm(m, n) * n } -gcd(52, 39) // 13 -gcd(228, 36) // 12 -gcd(51357, 3819) // 57 -gcd(841, 299) // 1 +gcdIterativeEuklid(52, 39) // 13 +gcdIterativeEuklid(228, 36) // 12 +gcdIterativeEuklid(51357, 3819) // 57 +gcdIterativeEuklid(841, 299) // 1 -lcm(2, 3) // 6 -lcm(10, 8) // 40 +gcdRecursiveEuklid(52, 39) // 13 +gcdRecursiveEuklid(228, 36) // 12 +gcdRecursiveEuklid(51357, 3819) // 57 +gcdRecursiveEuklid(841, 299) // 1 + +gcdBinaryRecursiveStein(52, 39) // 13 +gcdBinaryRecursiveStein(228, 36) // 12 +gcdBinaryRecursiveStein(51357, 3819) // 57 +gcdBinaryRecursiveStein(841, 299) // 1 + +do { + try lcm(2, 3, using: gcdIterativeEuklid) // 6 + try lcm(10, 8, using: gcdIterativeEuklid) // 40 +} catch { + dump(error) +} diff --git a/GCD/GCD.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/GCD/GCD.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/GCD/GCD.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/GCD/GCD.playground/timeline.xctimeline b/GCD/GCD.playground/timeline.xctimeline deleted file mode 100644 index bf468afec..000000000 --- a/GCD/GCD.playground/timeline.xctimeline +++ /dev/null @@ -1,6 +0,0 @@ - - - - - diff --git a/GCD/GCD.swift b/GCD/GCD.swift index bd903e58a..85b7681f0 100644 --- a/GCD/GCD.swift +++ b/GCD/GCD.swift @@ -1,34 +1,125 @@ + /* - Euclid's algorithm for finding the greatest common divisor -*/ -func gcd(_ m: Int, _ n: Int) -> Int { - var a = 0 - var b = max(m, n) - var r = min(m, n) + Iterative approach based on the Euclidean algorithm. + The Euclidean algorithm is based on the principle that the greatest + common divisor of two numbers does not change if the larger number + is replaced by its difference with the smaller number. + - Parameter m: First natural number + - Parameter n: Second natural number + - Returns: The natural gcd if m and n + */ +func gcdIterativeEuklid(_ m: Int, _ n: Int) -> Int { + var a: Int = 0 + var b: Int = max(m, n) + var r: Int = min(m, n) + + while r != 0 { + a = b + b = r + r = a % b + } + return b +} - while r != 0 { - a = b - b = r - r = a % b - } - return b +/* + Recursive approach based on the Euclidean algorithm. + + - Parameter m: First natural number + - Parameter n: Second natural number + - Returns: The natural gcd of m and n + - Note: The recursive version makes only tail recursive calls. + Most compilers for imperative languages do not optimize these. + The swift compiler as well as the obj-c compiler is able to do + optimizations for tail recursive calls, even though it still ends + up to be the same in terms of complexity. That said, tail call + elimination is not mutually exclusive to recursion. + */ +func gcdRecursiveEuklid(_ m: Int, _ n: Int) -> Int { + let r: Int = m % n + if r != 0 { + return gcdRecursiveEuklid(n, r) + } else { + return n + } } /* -// Recursive version -func gcd(_ a: Int, _ b: Int) -> Int { - let r = a % b - if r != 0 { - return gcd(b, r) - } else { - return b - } + The binary GCD algorithm, also known as Stein's algorithm, + is an algorithm that computes the greatest common divisor of two + nonnegative integers. Stein's algorithm uses simpler arithmetic + operations than the conventional Euclidean algorithm; it replaces + division with arithmetic shifts, comparisons, and subtraction. + + - Parameter m: First natural number + - Parameter n: Second natural number + - Returns: The natural gcd of m and n + - Complexity: worst case O(n^2), where n is the number of bits + in the larger of the two numbers. Although each step reduces + at least one of the operands by at least a factor of 2, + the subtract and shift operations take linear time for very + large integers + */ +func gcdBinaryRecursiveStein(_ m: Int, _ n: Int) -> Int { + if let easySolution = findEasySolution(m, n) { return easySolution } + + if (m & 1) == 0 { + // m is even + if (n & 1) == 1 { + // and n is odd + return gcdBinaryRecursiveStein(m >> 1, n) + } else { + // both m and n are even + return gcdBinaryRecursiveStein(m >> 1, n >> 1) << 1 + } + } else if (n & 1) == 0 { + // m is odd, n is even + return gcdBinaryRecursiveStein(m, n >> 1) + } else if (m > n) { + // reduce larger argument + return gcdBinaryRecursiveStein((m - n) >> 1, n) + } else { + // reduce larger argument + return gcdBinaryRecursiveStein((n - m) >> 1, m) + } +} + +/* + Finds an easy solution for the gcd. + - Note: It might be relevant for different usecases to + try finding an easy solution for the GCD calculation + before even starting more difficult operations. + */ +func findEasySolution(_ m: Int, _ n: Int) -> Int? { + if m == n { + return m + } + if m == 0 { + return n + } + if n == 0 { + return m + } + return nil +} + + +enum LCMError: Error { + case divisionByZero + case lcmEmptyList } -*/ /* - Returns the least common multiple of two numbers. -*/ -func lcm(_ m: Int, _ n: Int) -> Int { - return m / gcd(m, n) * n + Calculates the lcm for two given numbers using a specified gcd algorithm. + + - Parameter m: First natural number. + - Parameter n: Second natural number. + - Parameter using: The used gcd algorithm to calculate the lcm. + - Throws: Can throw a `divisionByZero` error if one of the given + attributes turns out to be zero or less. + - Returns: The least common multiplier of the two attributes as + an unsigned integer + */ +func lcm(_ m: Int, _ n: Int, using gcdAlgorithm: (Int, Int) -> (Int)) throws -> Int { + guard (m & n) != 0 else { throw LCMError.divisionByZero } + return m / gcdAlgorithm(m, n) * n } diff --git a/GCD/README.markdown b/GCD/README.markdown index d7e9304bd..a23aea190 100644 --- a/GCD/README.markdown +++ b/GCD/README.markdown @@ -1,8 +1,8 @@ # Greatest Common Divisor -The *greatest common divisor* (or Greatest Common Factor) of two numbers `a` and `b` is the largest positive integer that divides both `a` and `b` without a remainder. +The *greatest common divisor* (or Greatest Common Factor) of two numbers `a` and `b` is the largest positive integer that divides both `a` and `b` without a remainder. The GCD.swift file contains three different algorithms of how to calculate the greatest common divisor. -For example, `gcd(39, 52) = 13` because 13 divides 39 (`39/13 = 3`) as well as 52 (`52/13 = 4`). But there is no larger number than 13 that divides them both. +For example, `gcdIterativeEuklid(39, 52) = 13` because 13 divides 39 (`39/13 = 3`) as well as 52 (`52/13 = 4`). But there is no larger number than 13 that divides them both. You've probably had to learn about this in school at some point. :-) @@ -17,25 +17,25 @@ where `a % b` calculates the remainder of `a` divided by `b`. Here is an implementation of this idea in Swift: ```swift -func gcd(_ a: Int, _ b: Int) -> Int { - let r = a % b - if r != 0 { - return gcd(b, r) - } else { - return b - } +func gcdRecursiveEuklid(_ m: Int, _ n: Int) -> Int { + let r: Int = m % n + if r != 0 { + return gcdRecursiveEuklid(n, r) + } else { + return n + } } ``` Put it in a playground and try it out with these examples: ```swift -gcd(52, 39) // 13 -gcd(228, 36) // 12 -gcd(51357, 3819) // 57 +gcdBinaryRecursiveStein(52, 39) // 13 +gcdRecursiveEuklid(228, 36) // 12 +gcdIterativeEuklid(51357, 3819) // 57 ``` -Let's step through the third example: +Let's step through the third example using gcd as a representation of the gcdRecursiveEuklid here: gcd(51357, 3819) @@ -47,10 +47,10 @@ because the remainder of `51357 % 3819` is `1710`. If you work out this division So `gcd(51357, 3819)` is the same as `gcd(3819, 1710)`. That's useful because we can keep simplifying: - gcd(3819, 1710) = gcd(1710, 3819 % 1710) = - gcd(1710, 399) = gcd(399, 1710 % 399) = - gcd(399, 114) = gcd(114, 399 % 114) = - gcd(114, 57) = gcd(57, 114 % 57) = + gcd(3819, 1710) = gcd(1710, 3819 % 1710) = + gcd(1710, 399) = gcd(399, 1710 % 399) = + gcd(399, 114) = gcd(114, 399 % 114) = + gcd(114, 57) = gcd(57, 114 % 57) = gcd(57, 0) And now can't divide any further. The remainder of `114 / 57` is zero because `114 = 57 * 2` exactly. That means we've found the answer: @@ -68,17 +68,17 @@ gcd(841, 299) // 1 Here is a slightly different implementation of Euclid's algorithm. Unlike the first version this doesn't use recursion but only a basic `while` loop. ```swift -func gcd(_ m: Int, _ n: Int) -> Int { - var a = 0 - var b = max(m, n) - var r = min(m, n) - - while r != 0 { - a = b - b = r - r = a % b - } - return b +func gcdIterativeEuklid(_ m: Int, _ n: Int) -> Int { + var a: Int = 0 + var b: Int = max(m, n) + var r: Int = min(m, n) + + while r != 0 { + a = b + b = r + r = a % b + } + return b } ``` @@ -88,9 +88,9 @@ The `max()` and `min()` at the top of the function make sure we always divide th An idea related to the GCD is the *least common multiple* or LCM. -The least common multiple of two numbers `a` and `b` is the smallest positive integer that is a multiple of both. In other words, the LCM is evenly divisible by `a` and `b`. +The least common multiple of two numbers `a` and `b` is the smallest positive integer that is a multiple of both. In other words, the LCM is evenly divisible by `a` and `b`. The example implementation of the LCM takes two numbers and a specification which GCD algorithm is used. -For example: `lcm(2, 3) = 6` because 6 can be divided by 2 and also by 3. +For example: `lcm(2, 3, using: gcdIterativeEuklid) = 6` because 6 can be divided by 2 and also by 3. We can calculate the LCM using Euclid's algorithm too: @@ -101,17 +101,19 @@ We can calculate the LCM using Euclid's algorithm too: In code: ```swift -func lcm(_ m: Int, _ n: Int) -> Int { - return m / gcd(m, n) * n +func lcm(_ m: Int, _ n: Int, using gcdAlgorithm: (Int, Int) -> (Int)) throws -> Int { + guard (m & n) != 0 else { throw LCMError.divisionByZero } + return m / gcdAlgorithm(m, n) * n } ``` And to try it out in a playground: ```swift -lcm(10, 8) // 40 +lcm(10, 8, using: gcdIterativeEuklid) // 40 ``` You probably won't need to use the GCD or LCM in any real-world problems, but it's cool to play around with this ancient algorithm. It was first described by Euclid in his [Elements](http://publicdomainreview.org/collections/the-first-six-books-of-the-elements-of-euclid-1847/) around 300 BC. Rumor has it that he discovered this algorithm while he was hacking on his Commodore 64. *Written for Swift Algorithm Club by Matthijs Hollemans* +*Extended by Simon Krüger* \ No newline at end of file From 0f08fa9ddb315a55cca92d1fbabecb48a406cee8 Mon Sep 17 00:00:00 2001 From: Rahul Date: Tue, 23 Oct 2018 19:02:39 +0530 Subject: [PATCH 121/271] [Swift 4.2] Updated Selection Sort --- Selection Sort/SelectionSort.playground/Contents.swift | 5 ----- .../SelectionSort.playground/Sources/SelectionSort.swift | 2 +- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/Selection Sort/SelectionSort.playground/Contents.swift b/Selection Sort/SelectionSort.playground/Contents.swift index b16dadb8d..a552c9edb 100644 --- a/Selection Sort/SelectionSort.playground/Contents.swift +++ b/Selection Sort/SelectionSort.playground/Contents.swift @@ -1,10 +1,5 @@ //: Playground - noun: a place where people can play -// last checked with Xcode 9.0b4 -#if swift(>=4.0) -print("Hello, Swift 4!") -#endif - let list = [ 10, -1, 3, 9, 2, 27, 8, 5, 1, 3, 0, 26 ] selectionSort(list) selectionSort(list, <) diff --git a/Selection Sort/SelectionSort.playground/Sources/SelectionSort.swift b/Selection Sort/SelectionSort.playground/Sources/SelectionSort.swift index e7c66481d..e157319b4 100644 --- a/Selection Sort/SelectionSort.playground/Sources/SelectionSort.swift +++ b/Selection Sort/SelectionSort.playground/Sources/SelectionSort.swift @@ -3,7 +3,7 @@ /// - Parameter array: array of elements that conform to the Comparable protocol /// - Returns: an array in ascending order public func selectionSort(_ array: [T]) -> [T] { - return insertionSort(array, <) + return selectionSort(array, <) } /// Performs the Selection sort algorithm on a array using the provided comparisson method From e0c8738b1f1a16184d79158df9b65c6d42fc1568 Mon Sep 17 00:00:00 2001 From: Rahul Date: Tue, 23 Oct 2018 19:21:46 +0530 Subject: [PATCH 122/271] [Swift 4.2] Updated Linked List --- Linked List/LinkedList.playground/Contents.swift | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/Linked List/LinkedList.playground/Contents.swift b/Linked List/LinkedList.playground/Contents.swift index cfa3a8b45..76b911310 100644 --- a/Linked List/LinkedList.playground/Contents.swift +++ b/Linked List/LinkedList.playground/Contents.swift @@ -3,10 +3,6 @@ // For best results, don't forget to select "Show Rendered Markup" from XCode's "Editor" menu //: Linked List Class Declaration: -// last checked with Xcode 9.0b4 -#if swift(>=4.0) -print("Hello, Swift 4!") -#endif public final class LinkedList { @@ -459,7 +455,7 @@ var sum = 0 for element in collection { sum += element } -// sum is 15 +sum //15 // Another way of achieving the same result though 'reduce', another method defined in an extension of Sequence. Collections are Sequences. let result = collection.reduce(0) {$0 + $1} // 15 From 71b20f41f8e1926a3c4f10a8fc3eca05d98ab193 Mon Sep 17 00:00:00 2001 From: laurentaylormarshall Date: Tue, 23 Oct 2018 22:25:10 -0500 Subject: [PATCH 123/271] Removes Swift 4.0 checks and updates the Swift version to 4.2. --- Comb Sort/Comb Sort.playground/Contents.swift | 6 +---- Comb Sort/Tests/CombSortTests.swift | 1 + .../Tests/Tests.xcodeproj/project.pbxproj | 22 ++++++++++++++++--- .../xcshareddata/xcschemes/Tests.xcscheme | 2 +- 4 files changed, 22 insertions(+), 9 deletions(-) diff --git a/Comb Sort/Comb Sort.playground/Contents.swift b/Comb Sort/Comb Sort.playground/Contents.swift index 39e24248a..1f7723838 100644 --- a/Comb Sort/Comb Sort.playground/Contents.swift +++ b/Comb Sort/Comb Sort.playground/Contents.swift @@ -2,11 +2,7 @@ // Created by Stephen Rutstein // 7-16-2016 -import Cocoa -// last checked with Xcode 9.0b4 -#if swift(>=4.0) -print("Hello, Swift 4!") -#endif +import Foundation // Test Comb Sort with small array of ten values let array = [2, 32, 9, -1, 89, 101, 55, -10, -12, 67] diff --git a/Comb Sort/Tests/CombSortTests.swift b/Comb Sort/Tests/CombSortTests.swift index e972c0a57..783fbd150 100644 --- a/Comb Sort/Tests/CombSortTests.swift +++ b/Comb Sort/Tests/CombSortTests.swift @@ -17,6 +17,7 @@ class CombSortTests: XCTestCase { print("Hello, Swift 4!") #endif } + override func setUp() { super.setUp() sequence = [2, 32, 9, -1, 89, 101, 55, -10, -12, 67] diff --git a/Comb Sort/Tests/Tests.xcodeproj/project.pbxproj b/Comb Sort/Tests/Tests.xcodeproj/project.pbxproj index 7530acbdc..14d059271 100644 --- a/Comb Sort/Tests/Tests.xcodeproj/project.pbxproj +++ b/Comb Sort/Tests/Tests.xcodeproj/project.pbxproj @@ -82,7 +82,7 @@ isa = PBXProject; attributes = { LastSwiftUpdateCheck = 0820; - LastUpgradeCheck = 0820; + LastUpgradeCheck = 1000; ORGANIZATIONNAME = "Swift Algorithm Club"; TargetAttributes = { 056E92741E2483D300B30F52 = { @@ -142,15 +142,23 @@ CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_DOCUMENTATION_COMMENTS = YES; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; @@ -192,15 +200,23 @@ CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_DOCUMENTATION_COMMENTS = YES; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; @@ -235,7 +251,7 @@ PRODUCT_BUNDLE_IDENTIFIER = "Swift-Algorithm-Club.Tests"; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 4.0; + SWIFT_VERSION = 4.2; }; name = Debug; }; @@ -248,7 +264,7 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "Swift-Algorithm-Club.Tests"; PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 4.0; + SWIFT_VERSION = 4.2; }; name = Release; }; diff --git a/Comb Sort/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme b/Comb Sort/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme index 55e697ad3..48faa2df7 100644 --- a/Comb Sort/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme +++ b/Comb Sort/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme @@ -1,6 +1,6 @@ Date: Tue, 23 Oct 2018 22:40:49 -0500 Subject: [PATCH 124/271] Updates tests to check for Swift 4.2. Updates build settings to use Swift 4.2. --- Comb Sort/Tests/CombSortTests.swift | 6 +++--- Comb Sort/Tests/Tests.xcodeproj/project.pbxproj | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Comb Sort/Tests/CombSortTests.swift b/Comb Sort/Tests/CombSortTests.swift index 783fbd150..166065484 100644 --- a/Comb Sort/Tests/CombSortTests.swift +++ b/Comb Sort/Tests/CombSortTests.swift @@ -12,9 +12,9 @@ class CombSortTests: XCTestCase { var sequence: [Int]! let expectedSequence: [Int] = [-12, -10, -1, 2, 9, 32, 55, 67, 89, 101] - func testSwift4(){ - #if swift(>=4.0) - print("Hello, Swift 4!") + func testSwiftVersion(){ + #if swift(>=4.2) + print("Hello, Swift 4.2!") #endif } diff --git a/Comb Sort/Tests/Tests.xcodeproj/project.pbxproj b/Comb Sort/Tests/Tests.xcodeproj/project.pbxproj index 14d059271..4582b3f2d 100644 --- a/Comb Sort/Tests/Tests.xcodeproj/project.pbxproj +++ b/Comb Sort/Tests/Tests.xcodeproj/project.pbxproj @@ -187,7 +187,7 @@ SDKROOT = macosx; SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 4.0; + SWIFT_VERSION = 4.2; }; name = Debug; }; @@ -237,7 +237,7 @@ MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = macosx; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; - SWIFT_VERSION = 4.0; + SWIFT_VERSION = 4.2; }; name = Release; }; From 8da637c1d1c92cc65ea3eeb63275dc6117432b67 Mon Sep 17 00:00:00 2001 From: laurentaylormarshall Date: Tue, 23 Oct 2018 23:32:46 -0500 Subject: [PATCH 125/271] Removes Swift 4.0 check. Removes unused import. Refactors an if statement into a guard to be more Swift-y. --- Slow Sort/SlowSort.playground/Contents.swift | 5 ----- Slow Sort/SlowSort.swift | 7 ++----- 2 files changed, 2 insertions(+), 10 deletions(-) diff --git a/Slow Sort/SlowSort.playground/Contents.swift b/Slow Sort/SlowSort.playground/Contents.swift index 95bf80739..7c686782c 100644 --- a/Slow Sort/SlowSort.playground/Contents.swift +++ b/Slow Sort/SlowSort.playground/Contents.swift @@ -1,8 +1,3 @@ -// last checked with Xcode 9.0b4 -#if swift(>=4.0) -print("Hello, Swift 4!") -#endif - var numberList = [1, 12, 9, 17, 13, 12] slowsort(0, numberList.count-1, &numberList) diff --git a/Slow Sort/SlowSort.swift b/Slow Sort/SlowSort.swift index 9f264a057..c68a53455 100644 --- a/Slow Sort/SlowSort.swift +++ b/Slow Sort/SlowSort.swift @@ -6,12 +6,9 @@ // // -import Foundation - public func slowsort(_ i: Int, _ j: Int, _ numberList: inout [Int]) { - if i>=j { - return - } + guard i Date: Tue, 23 Oct 2018 23:41:43 -0500 Subject: [PATCH 126/271] Removes Swift 4.0 check. Removes unused import. Refactors an if statement into a guard to be more Swift-y. Removes unnecessarily explicitly defining the function as public. --- Slow Sort/SlowSort.playground/Contents.swift | 7 +------ Slow Sort/SlowSort.swift | 8 ++------ 2 files changed, 3 insertions(+), 12 deletions(-) diff --git a/Slow Sort/SlowSort.playground/Contents.swift b/Slow Sort/SlowSort.playground/Contents.swift index 95bf80739..54c1e61ea 100644 --- a/Slow Sort/SlowSort.playground/Contents.swift +++ b/Slow Sort/SlowSort.playground/Contents.swift @@ -1,9 +1,4 @@ -// last checked with Xcode 9.0b4 -#if swift(>=4.0) -print("Hello, Swift 4!") -#endif - var numberList = [1, 12, 9, 17, 13, 12] -slowsort(0, numberList.count-1, &numberList) +slowSort(0, numberList.count-1, &numberList) print(numberList) diff --git a/Slow Sort/SlowSort.swift b/Slow Sort/SlowSort.swift index 9f264a057..217733daa 100644 --- a/Slow Sort/SlowSort.swift +++ b/Slow Sort/SlowSort.swift @@ -6,12 +6,8 @@ // // -import Foundation - -public func slowsort(_ i: Int, _ j: Int, _ numberList: inout [Int]) { - if i>=j { - return - } +func slowSort(_ i: Int, _ j: Int, _ numberList: inout [Int]) { + guard if i < j else { return } let m = (i+j)/2 slowsort(i, m, &numberList) slowsort(m+1, j, &numberList) From 7add278a6acf10b19e2f8f035441b4a490d0125c Mon Sep 17 00:00:00 2001 From: laurentaylormarshall Date: Tue, 23 Oct 2018 23:43:25 -0500 Subject: [PATCH 127/271] Renames function to use camel case. --- Slow Sort/SlowSort.swift | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Slow Sort/SlowSort.swift b/Slow Sort/SlowSort.swift index 217733daa..c6e705fc7 100644 --- a/Slow Sort/SlowSort.swift +++ b/Slow Sort/SlowSort.swift @@ -9,12 +9,12 @@ func slowSort(_ i: Int, _ j: Int, _ numberList: inout [Int]) { guard if i < j else { return } let m = (i+j)/2 - slowsort(i, m, &numberList) - slowsort(m+1, j, &numberList) + slowSort(i, m, &numberList) + slowSort(m+1, j, &numberList) if numberList[j] < numberList[m] { let temp = numberList[j] numberList[j] = numberList[m] numberList[m] = temp } - slowsort(i, j-1, &numberList) + slowSort(i, j-1, &numberList) } From 227d6d9899d7f9abcc120fc04adc4a72119ee4ef Mon Sep 17 00:00:00 2001 From: laurentaylormarshall Date: Tue, 23 Oct 2018 23:50:21 -0500 Subject: [PATCH 128/271] Renames function to use camel case. --- Slow Sort/README.markdown | 14 ++++++-------- .../SlowSort.playground/Sources/SlowSort.swift | 13 ++++++------- 2 files changed, 12 insertions(+), 15 deletions(-) diff --git a/Slow Sort/README.markdown b/Slow Sort/README.markdown index f8cc743cc..f7742b6a3 100644 --- a/Slow Sort/README.markdown +++ b/Slow Sort/README.markdown @@ -17,19 +17,17 @@ We can decompose the problem of sorting n numbers in ascending order into Here is an implementation of slow sort in Swift: ```swift -public func slowsort(_ i: Int, _ j: Int) { - if i>=j { - return - } +func slowSort(_ i: Int, _ j: Int, _ numberList: inout [Int]) { + guard if i < j else { return } let m = (i+j)/2 - slowsort(i,m) - slowsort(m+1,j) + slowSort(i, m, &numberList) + slowSort(m+1, j, &numberList) if numberList[j] < numberList[m] { let temp = numberList[j] numberList[j] = numberList[m] numberList[m] = temp } - slowsort(i,j-1) + slowSort(i, j-1, &numberList) } ``` @@ -47,4 +45,4 @@ public func slowsort(_ i: Int, _ j: Int) { *Written for Swift Algorithm Club by Lukas Schramm* -(used the Insertion Sort Readme as template) \ No newline at end of file +(used the Insertion Sort Readme as template) diff --git a/Slow Sort/SlowSort.playground/Sources/SlowSort.swift b/Slow Sort/SlowSort.playground/Sources/SlowSort.swift index 32bb38505..cf09dcc5d 100644 --- a/Slow Sort/SlowSort.playground/Sources/SlowSort.swift +++ b/Slow Sort/SlowSort.playground/Sources/SlowSort.swift @@ -1,16 +1,15 @@ import Foundation -public func slowsort(_ i: Int, _ j: Int, _ numberList: inout [Int]) { - if i>=j { - return - } +public func slowSort(_ i: Int, _ j: Int, _ numberList: inout [Int]) { + guard i < j else { return } + let m = (i+j)/2 - slowsort(i, m, &numberList) - slowsort(m+1, j, &numberList) + slowSort(i, m, &numberList) + slowSort(m+1, j, &numberList) if numberList[j] < numberList[m] { let temp = numberList[j] numberList[j] = numberList[m] numberList[m] = temp } - slowsort(i, j-1, &numberList) + slowSort(i, j-1, &numberList) } From d3de867354ef9f639e991259e8722b9b9bb4e202 Mon Sep 17 00:00:00 2001 From: laurentaylormarshall Date: Wed, 24 Oct 2018 18:31:38 -0500 Subject: [PATCH 129/271] Updates build settings to use Swift 4.2. Removes references to checking for Swift version 4.0. Removes unused import. --- Quicksort/Quicksort.playground/Contents.swift | 5 ----- Quicksort/Tests/QuicksortTests.swift | 7 ------- Quicksort/Tests/SortingTestHelpers.swift | 1 - .../Tests/Tests-Quicksort.xcodeproj/project.pbxproj | 10 +++++++--- .../xcshareddata/xcschemes/Tests-Quicksort.xcscheme | 4 +--- 5 files changed, 8 insertions(+), 19 deletions(-) diff --git a/Quicksort/Quicksort.playground/Contents.swift b/Quicksort/Quicksort.playground/Contents.swift index 94d9f8e45..f0427731f 100644 --- a/Quicksort/Quicksort.playground/Contents.swift +++ b/Quicksort/Quicksort.playground/Contents.swift @@ -1,10 +1,5 @@ //: Playground - noun: a place where people can play -// last checked with Xcode 9.0b4 -#if swift(>=4.0) -print("Hello, Swift 4!") -#endif - import Foundation // *** Simple but inefficient version of quicksort *** diff --git a/Quicksort/Tests/QuicksortTests.swift b/Quicksort/Tests/QuicksortTests.swift index 0a8f1a2a8..c8d9a62e6 100644 --- a/Quicksort/Tests/QuicksortTests.swift +++ b/Quicksort/Tests/QuicksortTests.swift @@ -1,13 +1,6 @@ import XCTest class QuicksortTests: XCTestCase { - func testSwift4() { - // last checked with Xcode 9.0b4 - #if swift(>=4.0) - print("Hello, Swift 4!") - #endif - } - func testQuicksort() { checkSortAlgorithm(quicksort) } diff --git a/Quicksort/Tests/SortingTestHelpers.swift b/Quicksort/Tests/SortingTestHelpers.swift index d699ec1e4..0c47cde4e 100644 --- a/Quicksort/Tests/SortingTestHelpers.swift +++ b/Quicksort/Tests/SortingTestHelpers.swift @@ -1,4 +1,3 @@ -import Foundation import XCTest func randomArray(_ size: Int) -> [Int] { diff --git a/Quicksort/Tests/Tests-Quicksort.xcodeproj/project.pbxproj b/Quicksort/Tests/Tests-Quicksort.xcodeproj/project.pbxproj index c1b14e727..923195121 100644 --- a/Quicksort/Tests/Tests-Quicksort.xcodeproj/project.pbxproj +++ b/Quicksort/Tests/Tests-Quicksort.xcodeproj/project.pbxproj @@ -86,7 +86,7 @@ isa = PBXProject; attributes = { LastSwiftUpdateCheck = 0720; - LastUpgradeCheck = 0900; + LastUpgradeCheck = 1000; ORGANIZATIONNAME = "Swift Algorithm Club"; TargetAttributes = { 7B2BBC7F1C779D720067B71D = { @@ -149,12 +149,14 @@ CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; @@ -187,7 +189,7 @@ SDKROOT = macosx; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_SWIFT3_OBJC_INFERENCE = Off; - SWIFT_VERSION = 4.0; + SWIFT_VERSION = 4.2; }; name = Debug; }; @@ -203,12 +205,14 @@ CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; @@ -234,7 +238,7 @@ SDKROOT = macosx; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; SWIFT_SWIFT3_OBJC_INFERENCE = Off; - SWIFT_VERSION = 4.0; + SWIFT_VERSION = 4.2; }; name = Release; }; diff --git a/Quicksort/Tests/Tests-Quicksort.xcodeproj/xcshareddata/xcschemes/Tests-Quicksort.xcscheme b/Quicksort/Tests/Tests-Quicksort.xcodeproj/xcshareddata/xcschemes/Tests-Quicksort.xcscheme index 5b67c6f70..ec81527d1 100644 --- a/Quicksort/Tests/Tests-Quicksort.xcodeproj/xcshareddata/xcschemes/Tests-Quicksort.xcscheme +++ b/Quicksort/Tests/Tests-Quicksort.xcodeproj/xcshareddata/xcschemes/Tests-Quicksort.xcscheme @@ -1,6 +1,6 @@ Date: Fri, 26 Oct 2018 12:17:59 +0200 Subject: [PATCH 130/271] Updated Binary Tree to Swift 4.2 --- Binary Tree/BinaryTree.playground/Contents.swift | 5 ----- Binary Tree/BinaryTree.playground/contents.xcplayground | 2 +- .../xcshareddata/IDEWorkspaceChecks.plist | 8 ++++++++ 3 files changed, 9 insertions(+), 6 deletions(-) create mode 100644 Binary Tree/BinaryTree.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist diff --git a/Binary Tree/BinaryTree.playground/Contents.swift b/Binary Tree/BinaryTree.playground/Contents.swift index 9da194fed..b0bff577a 100644 --- a/Binary Tree/BinaryTree.playground/Contents.swift +++ b/Binary Tree/BinaryTree.playground/Contents.swift @@ -1,10 +1,5 @@ //: Playground - noun: a place where people can play -// last checked with Xcode 9.0b4 -#if swift(>=4.0) -print("Hello, Swift 4!") -#endif - public indirect enum BinaryTree { case node(BinaryTree, T, BinaryTree) case empty diff --git a/Binary Tree/BinaryTree.playground/contents.xcplayground b/Binary Tree/BinaryTree.playground/contents.xcplayground index 06828af92..69d154d1e 100644 --- a/Binary Tree/BinaryTree.playground/contents.xcplayground +++ b/Binary Tree/BinaryTree.playground/contents.xcplayground @@ -1,4 +1,4 @@ - + \ No newline at end of file diff --git a/Binary Tree/BinaryTree.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Binary Tree/BinaryTree.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/Binary Tree/BinaryTree.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + From 016ae7c90bc525246f925480b6c6aa92eab47e4f Mon Sep 17 00:00:00 2001 From: Marc Date: Fri, 26 Oct 2018 12:21:05 +0200 Subject: [PATCH 131/271] Update BitSet to Swift 4.2 --- Bit Set/BitSet.playground/Contents.swift | 5 ----- Bit Set/BitSet.playground/contents.xcplayground | 2 +- .../xcshareddata/IDEWorkspaceChecks.plist | 8 ++++++++ 3 files changed, 9 insertions(+), 6 deletions(-) create mode 100644 Bit Set/BitSet.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist diff --git a/Bit Set/BitSet.playground/Contents.swift b/Bit Set/BitSet.playground/Contents.swift index 95253ea27..d11b36e8c 100644 --- a/Bit Set/BitSet.playground/Contents.swift +++ b/Bit Set/BitSet.playground/Contents.swift @@ -1,10 +1,5 @@ //: Playground - noun: a place where people can play -// last checked with Xcode 9.0b4 -#if swift(>=4.0) -print("Hello, Swift 4!") -#endif - // Create a bit set that stores 140 bits var bits = BitSet(size: 140) diff --git a/Bit Set/BitSet.playground/contents.xcplayground b/Bit Set/BitSet.playground/contents.xcplayground index 06828af92..69d154d1e 100644 --- a/Bit Set/BitSet.playground/contents.xcplayground +++ b/Bit Set/BitSet.playground/contents.xcplayground @@ -1,4 +1,4 @@ - + \ No newline at end of file diff --git a/Bit Set/BitSet.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Bit Set/BitSet.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/Bit Set/BitSet.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + From 6d8e795377902dc7dbdc6ad0a2231f62ba3a0d49 Mon Sep 17 00:00:00 2001 From: Marc Date: Fri, 26 Oct 2018 12:31:47 +0200 Subject: [PATCH 132/271] Update Bounded Priority Queue to Swift 4.2 --- .../BoundedPriorityQueue.playground/Contents.swift | 5 ----- .../BoundedPriorityQueue.playground/contents.xcplayground | 2 +- .../xcshareddata/IDEWorkspaceChecks.plist | 8 ++++++++ .../Tests/Tests.xcodeproj/project.pbxproj | 6 +++--- .../xcshareddata/IDEWorkspaceChecks.plist | 8 ++++++++ 5 files changed, 20 insertions(+), 9 deletions(-) create mode 100644 Bounded Priority Queue/BoundedPriorityQueue.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist create mode 100644 Bounded Priority Queue/Tests/Tests.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist diff --git a/Bounded Priority Queue/BoundedPriorityQueue.playground/Contents.swift b/Bounded Priority Queue/BoundedPriorityQueue.playground/Contents.swift index f8e219c13..d6204abec 100644 --- a/Bounded Priority Queue/BoundedPriorityQueue.playground/Contents.swift +++ b/Bounded Priority Queue/BoundedPriorityQueue.playground/Contents.swift @@ -1,8 +1,3 @@ -// last checked with Xcode 9.0b4 -#if swift(>=4.0) -print("Hello, Swift 4!") -#endif - struct Message: Comparable, CustomStringConvertible { let name: String let priority: Int diff --git a/Bounded Priority Queue/BoundedPriorityQueue.playground/contents.xcplayground b/Bounded Priority Queue/BoundedPriorityQueue.playground/contents.xcplayground index 06828af92..69d154d1e 100644 --- a/Bounded Priority Queue/BoundedPriorityQueue.playground/contents.xcplayground +++ b/Bounded Priority Queue/BoundedPriorityQueue.playground/contents.xcplayground @@ -1,4 +1,4 @@ - + \ No newline at end of file diff --git a/Bounded Priority Queue/BoundedPriorityQueue.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Bounded Priority Queue/BoundedPriorityQueue.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/Bounded Priority Queue/BoundedPriorityQueue.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/Bounded Priority Queue/Tests/Tests.xcodeproj/project.pbxproj b/Bounded Priority Queue/Tests/Tests.xcodeproj/project.pbxproj index 842c51695..11f907b47 100644 --- a/Bounded Priority Queue/Tests/Tests.xcodeproj/project.pbxproj +++ b/Bounded Priority Queue/Tests/Tests.xcodeproj/project.pbxproj @@ -86,7 +86,7 @@ TargetAttributes = { B80004B21C83E342001FE2D7 = { CreatedOnToolsVersion = 7.2.1; - LastSwiftMigration = 0820; + LastSwiftMigration = 1000; }; }; }; @@ -226,7 +226,7 @@ SDKROOT = macosx; SWIFT_OBJC_BRIDGING_HEADER = ""; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 3.0; + SWIFT_VERSION = 4.2; }; name = Debug; }; @@ -269,7 +269,7 @@ PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = macosx; SWIFT_OBJC_BRIDGING_HEADER = ""; - SWIFT_VERSION = 3.0; + SWIFT_VERSION = 4.2; }; name = Release; }; diff --git a/Bounded Priority Queue/Tests/Tests.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Bounded Priority Queue/Tests/Tests.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/Bounded Priority Queue/Tests/Tests.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + From 57f25c429638b6a607d3e67f9e70f3633e2a1045 Mon Sep 17 00:00:00 2001 From: Marc Date: Fri, 26 Oct 2018 13:16:15 +0200 Subject: [PATCH 133/271] Update Boyer Moore to Swift 4.2 --- .../BoyerMooreHorspool.playground/Contents.swift | 11 +++-------- .../xcshareddata/IDEWorkspaceChecks.plist | 8 ++++++++ Boyer-Moore-Horspool/BoyerMooreHorspool.swift | 6 +++--- Boyer-Moore-Horspool/Tests/BoyerMooreTests.swift | 4 ++-- .../Tests/Tests.xcodeproj/project.pbxproj | 14 ++++++++------ .../xcshareddata/IDEWorkspaceChecks.plist | 8 ++++++++ .../xcshareddata/xcschemes/Tests.xcscheme | 4 +--- .../contents.xcworkspacedata | 6 +++--- 8 files changed, 36 insertions(+), 25 deletions(-) create mode 100644 Boyer-Moore-Horspool/BoyerMooreHorspool.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist create mode 100644 Boyer-Moore-Horspool/Tests/Tests.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist diff --git a/Boyer-Moore-Horspool/BoyerMooreHorspool.playground/Contents.swift b/Boyer-Moore-Horspool/BoyerMooreHorspool.playground/Contents.swift index e88a1b93d..1666549c1 100644 --- a/Boyer-Moore-Horspool/BoyerMooreHorspool.playground/Contents.swift +++ b/Boyer-Moore-Horspool/BoyerMooreHorspool.playground/Contents.swift @@ -1,10 +1,5 @@ //: Playground - noun: a place where people can play -// last checked with Xcode 9.0b4 -#if swift(>=4.0) - print("Hello, Swift 4!") -#endif - /* Boyer-Moore string search @@ -16,13 +11,13 @@ extension String { func index(of pattern: String, usingHorspoolImprovement: Bool = false) -> Index? { // Cache the length of the search pattern because we're going to // use it a few times and it's expensive to calculate. - let patternLength = pattern.characters.count - guard patternLength > 0, patternLength <= characters.count else { return nil } + let patternLength = pattern.count + guard patternLength > 0, patternLength <= count else { return nil } // Make the skip table. This table determines how far we skip ahead // when a character from the pattern is found. var skipTable = [Character: Int]() - for (i, c) in pattern.characters.enumerated() { + for (i, c) in pattern.enumerated() { skipTable[c] = patternLength - i - 1 } diff --git a/Boyer-Moore-Horspool/BoyerMooreHorspool.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Boyer-Moore-Horspool/BoyerMooreHorspool.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/Boyer-Moore-Horspool/BoyerMooreHorspool.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/Boyer-Moore-Horspool/BoyerMooreHorspool.swift b/Boyer-Moore-Horspool/BoyerMooreHorspool.swift index af8aea9d9..dbd738740 100644 --- a/Boyer-Moore-Horspool/BoyerMooreHorspool.swift +++ b/Boyer-Moore-Horspool/BoyerMooreHorspool.swift @@ -9,13 +9,13 @@ extension String { func index(of pattern: String, usingHorspoolImprovement: Bool = false) -> Index? { // Cache the length of the search pattern because we're going to // use it a few times and it's expensive to calculate. - let patternLength = pattern.characters.count - guard patternLength > 0, patternLength <= characters.count else { return nil } + let patternLength = pattern.count + guard patternLength > 0, patternLength <= count else { return nil } // Make the skip table. This table determines how far we skip ahead // when a character from the pattern is found. var skipTable = [Character: Int]() - for (i, c) in pattern.characters.enumerated() { + for (i, c) in pattern.enumerated() { skipTable[c] = patternLength - i - 1 } diff --git a/Boyer-Moore-Horspool/Tests/BoyerMooreTests.swift b/Boyer-Moore-Horspool/Tests/BoyerMooreTests.swift index 9efe60874..436173127 100755 --- a/Boyer-Moore-Horspool/Tests/BoyerMooreTests.swift +++ b/Boyer-Moore-Horspool/Tests/BoyerMooreTests.swift @@ -26,8 +26,8 @@ class BoyerMooreTest: XCTestCase { XCTAssertNotNil(index) let startIndex = index! - let endIndex = string.index(index!, offsetBy: pattern.characters.count) - let match = string.substring(with: startIndex.. + + + + IDEDidComputeMac32BitWarning + + + diff --git a/Boyer-Moore-Horspool/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme b/Boyer-Moore-Horspool/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme index 538a6f4fa..afd69e6a7 100644 --- a/Boyer-Moore-Horspool/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme +++ b/Boyer-Moore-Horspool/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme @@ -1,6 +1,6 @@ + location = "group:Boyer-Moore-Horspool/BoyerMooreHorspool.playground"> + location = "group:Boyer-Moore-Horspool/BoyerMooreHorspool.swift"> From 7384ec29e4e95cbae0b6a93dc6ae2ffe66eecffb Mon Sep 17 00:00:00 2001 From: Marc Date: Fri, 26 Oct 2018 13:20:32 +0200 Subject: [PATCH 134/271] Update Boyer Moore to Swift 4.2 --- .../contents.xcworkspacedata | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/swift-algorithm-club.xcworkspace/contents.xcworkspacedata b/swift-algorithm-club.xcworkspace/contents.xcworkspacedata index 04d4ac573..d85d538b3 100644 --- a/swift-algorithm-club.xcworkspace/contents.xcworkspacedata +++ b/swift-algorithm-club.xcworkspace/contents.xcworkspacedata @@ -609,19 +609,19 @@ + location = "group:BoyerMooreHorspool.playground"> + location = "group:BoyerMooreHorspool.swift"> @@ -633,7 +633,7 @@ location = "group:Info.plist"> + location = "group:/Users/mroedder/workspace/swift-algorithm-club/Boyer-Moore-Horspool/Tests/Tests.xcodeproj"> From 402f23669b3f5c06dbd64adfe885d873e3a23f65 Mon Sep 17 00:00:00 2001 From: Marc Date: Fri, 26 Oct 2018 13:24:39 +0200 Subject: [PATCH 135/271] Update Boyer Moore to Swift 4.2 --- swift-algorithm-club.xcworkspace/contents.xcworkspacedata | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/swift-algorithm-club.xcworkspace/contents.xcworkspacedata b/swift-algorithm-club.xcworkspace/contents.xcworkspacedata index d85d538b3..a37dac494 100644 --- a/swift-algorithm-club.xcworkspace/contents.xcworkspacedata +++ b/swift-algorithm-club.xcworkspace/contents.xcworkspacedata @@ -633,7 +633,7 @@ location = "group:Info.plist"> + location = "group:Tests/Tests.xcodeproj"> From 6ead6d0dcb0e77f51cbda0582a1b6f56c1d0ebd0 Mon Sep 17 00:00:00 2001 From: Marc Date: Fri, 26 Oct 2018 13:27:09 +0200 Subject: [PATCH 136/271] Update README to use Swift 4.2 --- Boyer-Moore-Horspool/README.markdown | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Boyer-Moore-Horspool/README.markdown b/Boyer-Moore-Horspool/README.markdown index f5e21ea41..8879d8df6 100644 --- a/Boyer-Moore-Horspool/README.markdown +++ b/Boyer-Moore-Horspool/README.markdown @@ -38,13 +38,13 @@ extension String { func index(of pattern: String) -> Index? { // Cache the length of the search pattern because we're going to // use it a few times and it's expensive to calculate. - let patternLength = pattern.characters.count - guard patternLength > 0, patternLength <= characters.count else { return nil } + let patternLength = pattern.count + guard patternLength > 0, patternLength <= count else { return nil } // Make the skip table. This table determines how far we skip ahead // when a character from the pattern is found. var skipTable = [Character: Int]() - for (i, c) in pattern.characters.enumerated() { + for (i, c) in pattern.enumerated() { skipTable[c] = patternLength - i - 1 } @@ -162,13 +162,13 @@ extension String { func index(of pattern: String) -> Index? { // Cache the length of the search pattern because we're going to // use it a few times and it's expensive to calculate. - let patternLength = pattern.characters.count + let patternLength = pattern.count guard patternLength > 0, patternLength <= characters.count else { return nil } // Make the skip table. This table determines how far we skip ahead // when a character from the pattern is found. var skipTable = [Character: Int]() - for (i, c) in pattern.characters.enumerated() { + for (i, c) in pattern.enumerated() { skipTable[c] = patternLength - i - 1 } From 13d152600da95a0864d14edae72c0d93c161781c Mon Sep 17 00:00:00 2001 From: Marc Date: Fri, 26 Oct 2018 13:41:18 +0200 Subject: [PATCH 137/271] Update Breadth First Search to Swift 4.2 --- .../Contents.swift | 4 --- .../Sources/Graph.swift | 2 +- .../contents.xcplayground | 2 +- .../xcshareddata/IDEWorkspaceChecks.plist | 8 +++++ .../Tests/Tests.xcodeproj/project.pbxproj | 30 +++++++++++++++---- .../xcshareddata/IDEWorkspaceChecks.plist | 8 +++++ .../xcshareddata/xcschemes/Tests.xcscheme | 2 +- 7 files changed, 44 insertions(+), 12 deletions(-) create mode 100644 Breadth-First Search/BreadthFirstSearch.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist create mode 100644 Breadth-First Search/Tests/Tests.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist diff --git a/Breadth-First Search/BreadthFirstSearch.playground/Pages/Simple example.xcplaygroundpage/Contents.swift b/Breadth-First Search/BreadthFirstSearch.playground/Pages/Simple example.xcplaygroundpage/Contents.swift index 3986a0cee..cf22ebb25 100644 --- a/Breadth-First Search/BreadthFirstSearch.playground/Pages/Simple example.xcplaygroundpage/Contents.swift +++ b/Breadth-First Search/BreadthFirstSearch.playground/Pages/Simple example.xcplaygroundpage/Contents.swift @@ -1,7 +1,3 @@ -// last checked with Xcode 9.0b4 -#if swift(>=4.0) -print("Hello, Swift 4!") -#endif func breadthFirstSearch(_ graph: Graph, source: Node) -> [String] { var queue = Queue() diff --git a/Breadth-First Search/BreadthFirstSearch.playground/Sources/Graph.swift b/Breadth-First Search/BreadthFirstSearch.playground/Sources/Graph.swift index 87e21897c..0343120f8 100644 --- a/Breadth-First Search/BreadthFirstSearch.playground/Sources/Graph.swift +++ b/Breadth-First Search/BreadthFirstSearch.playground/Sources/Graph.swift @@ -5,7 +5,7 @@ public class Graph: CustomStringConvertible, Equatable { self.nodes = [] } - public func addNode(_ label: String) -> Node { + @discardableResult public func addNode(_ label: String) -> Node { let node = Node(label) nodes.append(node) return node diff --git a/Breadth-First Search/BreadthFirstSearch.playground/contents.xcplayground b/Breadth-First Search/BreadthFirstSearch.playground/contents.xcplayground index 513c2e7e9..f635e9804 100644 --- a/Breadth-First Search/BreadthFirstSearch.playground/contents.xcplayground +++ b/Breadth-First Search/BreadthFirstSearch.playground/contents.xcplayground @@ -1,2 +1,2 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/Breadth-First Search/BreadthFirstSearch.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Breadth-First Search/BreadthFirstSearch.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/Breadth-First Search/BreadthFirstSearch.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/Breadth-First Search/Tests/Tests.xcodeproj/project.pbxproj b/Breadth-First Search/Tests/Tests.xcodeproj/project.pbxproj index f86abf86e..a7f04e00a 100644 --- a/Breadth-First Search/Tests/Tests.xcodeproj/project.pbxproj +++ b/Breadth-First Search/Tests/Tests.xcodeproj/project.pbxproj @@ -59,7 +59,6 @@ 7B2BBC941C779E7B0067B71D /* Info.plist */, ); name = Tests; - path = TestsTests; sourceTree = ""; }; /* End PBXGroup section */ @@ -89,12 +88,12 @@ isa = PBXProject; attributes = { LastSwiftUpdateCheck = 0720; - LastUpgradeCheck = 0820; + LastUpgradeCheck = 1000; ORGANIZATIONNAME = "Swift Algorithm Club"; TargetAttributes = { 7B2BBC7F1C779D720067B71D = { CreatedOnToolsVersion = 7.2; - LastSwiftMigration = 0820; + LastSwiftMigration = 1000; }; }; }; @@ -149,13 +148,23 @@ CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_IDENTITY = "-"; @@ -193,13 +202,23 @@ CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_IDENTITY = "-"; @@ -218,6 +237,7 @@ MACOSX_DEPLOYMENT_TARGET = 10.11; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = macosx; + SWIFT_COMPILATION_MODE = wholemodule; }; name = Release; }; @@ -231,7 +251,7 @@ PRODUCT_BUNDLE_IDENTIFIER = swift.algorithm.club.Tests; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 3.0; + SWIFT_VERSION = 4.2; }; name = Debug; }; @@ -244,7 +264,7 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = swift.algorithm.club.Tests; PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 3.0; + SWIFT_VERSION = 4.2; }; name = Release; }; diff --git a/Breadth-First Search/Tests/Tests.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Breadth-First Search/Tests/Tests.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/Breadth-First Search/Tests/Tests.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/Breadth-First Search/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme b/Breadth-First Search/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme index dfcf6de42..afd69e6a7 100644 --- a/Breadth-First Search/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme +++ b/Breadth-First Search/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme @@ -1,6 +1,6 @@ Date: Fri, 26 Oct 2018 14:33:49 +0200 Subject: [PATCH 138/271] Extended Miller-Rabin Primality test [code] * Adds a more readable documentation and clear naming for variables to the Miller-Rabin Primality Test example * Miller-Rabin can fail under certain situations. These have to throw an error. * Updates the relevant playground files * Add name to documentation --- .../MRPrimality.playground/Contents.swift | 46 ++--- .../Sources/MRPrimality.swift | 111 ------------ .../Sources/MillerRabin.swift | 100 +++++++++++ .../contents.xcworkspacedata | 7 + .../xcshareddata/IDEWorkspaceChecks.plist | 8 + Miller-Rabin Primality Test/MRPrimality.swift | 169 ++++++++---------- Miller-Rabin Primality Test/README.markdown | 5 +- 7 files changed, 221 insertions(+), 225 deletions(-) delete mode 100644 Miller-Rabin Primality Test/MRPrimality.playground/Sources/MRPrimality.swift create mode 100644 Miller-Rabin Primality Test/MRPrimality.playground/Sources/MillerRabin.swift create mode 100644 Miller-Rabin Primality Test/MRPrimality.playground/playground.xcworkspace/contents.xcworkspacedata create mode 100644 Miller-Rabin Primality Test/MRPrimality.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist diff --git a/Miller-Rabin Primality Test/MRPrimality.playground/Contents.swift b/Miller-Rabin Primality Test/MRPrimality.playground/Contents.swift index d8fd7fad8..1e4113c15 100644 --- a/Miller-Rabin Primality Test/MRPrimality.playground/Contents.swift +++ b/Miller-Rabin Primality Test/MRPrimality.playground/Contents.swift @@ -5,25 +5,27 @@ print("Hello, Swift 4!") #endif -// Real primes -mrPrimalityTest(5) -mrPrimalityTest(439) -mrPrimalityTest(1201) -mrPrimalityTest(143477) -mrPrimalityTest(1299869) -mrPrimalityTest(15487361) -mrPrimalityTest(179426363) -mrPrimalityTest(32416187747) - -// Fake primes -mrPrimalityTest(15) -mrPrimalityTest(435) -mrPrimalityTest(1207) -mrPrimalityTest(143473) -mrPrimalityTest(1291869) -mrPrimalityTest(15487161) -mrPrimalityTest(178426363) -mrPrimalityTest(32415187747) - -// With iteration -mrPrimalityTest(32416190071, iteration: 10) +do { + // Real primes + try checkWithMillerRabin(5) + try checkWithMillerRabin(439) + try checkWithMillerRabin(1201) + try checkWithMillerRabin(143477) + try checkWithMillerRabin(1299869) + try checkWithMillerRabin(15487361) + try checkWithMillerRabin(179426363) + + // Fake primes + try checkWithMillerRabin(15) + try checkWithMillerRabin(435) + try checkWithMillerRabin(1207) + try checkWithMillerRabin(143473) + try checkWithMillerRabin(1291869) + try checkWithMillerRabin(15487161) + try checkWithMillerRabin(178426363) + + // Specifying accuracy + try checkWithMillerRabin(179426363, accuracy: 10) +} catch { + dump(error) +} diff --git a/Miller-Rabin Primality Test/MRPrimality.playground/Sources/MRPrimality.swift b/Miller-Rabin Primality Test/MRPrimality.playground/Sources/MRPrimality.swift deleted file mode 100644 index ee2ace8b9..000000000 --- a/Miller-Rabin Primality Test/MRPrimality.playground/Sources/MRPrimality.swift +++ /dev/null @@ -1,111 +0,0 @@ -// -// MRPrimality.swift -// -// -// Created by Sahn Cha on 2016. 10. 18.. -// -// - -import Foundation - -/* - Miller-Rabin Primality Test. - One of the most used algorithms for primality testing. - Since this is a probabilistic algorithm, it needs to be executed multiple times to increase accuracy. - - Inputs: - n: UInt64 { target integer to be tested for primality } - k: Int { optional. number of iterations } - - Outputs: - true { probably prime } - false { composite } - */ -public func mrPrimalityTest(_ n: UInt64, iteration k: Int = 1) -> Bool { - guard n > 2 && n % 2 == 1 else { return false } - - var d = n - 1 - var s = 0 - - while d % 2 == 0 { - d /= 2 - s += 1 - } - - let range = UInt64.max - UInt64.max % (n - 2) - var r: UInt64 = 0 - repeat { - arc4random_buf(&r, MemoryLayout.size(ofValue: r)) - } while r >= range - - r = r % (n - 2) + 2 - - for _ in 1 ... k { - var x = powmod64(r, d, n) - if x == 1 || x == n - 1 { continue } - - if s == 1 { s = 2 } - - for _ in 1 ... s - 1 { - x = powmod64(x, 2, n) - if x == 1 { return false } - if x == n - 1 { break } - } - - if x != n - 1 { return false } - } - - return true -} - -/* - Calculates (base^exp) mod m. - - Inputs: - base: UInt64 { base } - exp: UInt64 { exponent } - m: UInt64 { modulus } - - Outputs: - the result - */ -private func powmod64(_ base: UInt64, _ exp: UInt64, _ m: UInt64) -> UInt64 { - if m == 1 { return 0 } - - var result: UInt64 = 1 - var b = base % m - var e = exp - - while e > 0 { - if e % 2 == 1 { result = mulmod64(result, b, m) } - b = mulmod64(b, b, m) - e >>= 1 - } - - return result -} - -/* - Calculates (first * second) mod m, hopefully without overflow. :] - - Inputs: - first: UInt64 { first integer } - second: UInt64 { second integer } - m: UInt64 { modulus } - - Outputs: - the result - */ -private func mulmod64(_ first: UInt64, _ second: UInt64, _ m: UInt64) -> UInt64 { - var result: UInt64 = 0 - var a = first - var b = second - - while a != 0 { - if a % 2 == 1 { result = ((result % m) + (b % m)) % m } // This may overflow if 'm' is a 64bit number && both 'result' and 'b' are very close to but smaller than 'm'. - a >>= 1 - b = (b << 1) % m - } - - return result -} diff --git a/Miller-Rabin Primality Test/MRPrimality.playground/Sources/MillerRabin.swift b/Miller-Rabin Primality Test/MRPrimality.playground/Sources/MillerRabin.swift new file mode 100644 index 000000000..03daac1fa --- /dev/null +++ b/Miller-Rabin Primality Test/MRPrimality.playground/Sources/MillerRabin.swift @@ -0,0 +1,100 @@ +// +// MRPrimality.swift +// +// +// Created by Sahn Cha on 2016. 10. 18.. +// +// + +import Foundation + +enum MillerRabinError: Error { + case primeLowAccuracy + case primeLowerBorder + case uIntOverflow +} + +/* + The Miller–Rabin test relies on an equality or set of equalities that + hold true for prime values, then checks whether or not they hold for + a number that we want to test for primality. + + - Parameter n: an odd integer to be tested for primality; + - Parameter k: a parameter that determines the accuracy of the test + - throws: Can throw an error of type `MillerRabinError`. + - Returns: composite if n is composite, otherwise probably prime + */ +public func checkWithMillerRabin(_ n: UInt, accuracy k: UInt = 1) throws -> Bool { + guard k > 0 else { throw MillerRabinError.primeLowAccuracy } + guard n > 0 else { throw MillerRabinError.primeLowerBorder } + guard n > 3 else { return true } + + // return false for all even numbers bigger than 2 + if n % 2 == 0 { + return false + } + + let s: UInt = UInt((n - 1).trailingZeroBitCount) + let d: UInt = (n - 1) >> s + + guard UInt(pow(2.0, Double(s))) * d == n - 1 else { throw MillerRabinError.primeLowerBorder } + + /// Inspect whether a given witness will reveal the true identity of n. + func tryComposite(_ a: UInt, d: UInt, n: UInt) throws -> Bool? { + var x = try calculateModularExponentiation(base: a, exponent: d, modulus: n) + if x == 1 || x == (n - 1) { + return nil + } + for _ in 1.. UInt { + guard modulus > 1 else { return 0 } + guard !(modulus-1).multipliedReportingOverflow(by: (modulus-1)).overflow else { + throw MillerRabinError.uIntOverflow + } + + var result: UInt = 1 + var exponentCopy = exponent + var baseCopy = base % modulus + + while exponentCopy > 0 { + if exponentCopy % 2 == 1 { + result = (result * baseCopy) % modulus + } + exponentCopy = exponentCopy >> 1 + baseCopy = (baseCopy * baseCopy) % modulus + } + + return result +} diff --git a/Miller-Rabin Primality Test/MRPrimality.playground/playground.xcworkspace/contents.xcworkspacedata b/Miller-Rabin Primality Test/MRPrimality.playground/playground.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..919434a62 --- /dev/null +++ b/Miller-Rabin Primality Test/MRPrimality.playground/playground.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/Miller-Rabin Primality Test/MRPrimality.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Miller-Rabin Primality Test/MRPrimality.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/Miller-Rabin Primality Test/MRPrimality.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/Miller-Rabin Primality Test/MRPrimality.swift b/Miller-Rabin Primality Test/MRPrimality.swift index ee2ace8b9..24b9c674c 100644 --- a/Miller-Rabin Primality Test/MRPrimality.swift +++ b/Miller-Rabin Primality Test/MRPrimality.swift @@ -1,6 +1,6 @@ // // MRPrimality.swift -// +// // // Created by Sahn Cha on 2016. 10. 18.. // @@ -8,104 +8,93 @@ import Foundation -/* - Miller-Rabin Primality Test. - One of the most used algorithms for primality testing. - Since this is a probabilistic algorithm, it needs to be executed multiple times to increase accuracy. - - Inputs: - n: UInt64 { target integer to be tested for primality } - k: Int { optional. number of iterations } - - Outputs: - true { probably prime } - false { composite } - */ -public func mrPrimalityTest(_ n: UInt64, iteration k: Int = 1) -> Bool { - guard n > 2 && n % 2 == 1 else { return false } - - var d = n - 1 - var s = 0 - - while d % 2 == 0 { - d /= 2 - s += 1 - } - - let range = UInt64.max - UInt64.max % (n - 2) - var r: UInt64 = 0 - repeat { - arc4random_buf(&r, MemoryLayout.size(ofValue: r)) - } while r >= range - - r = r % (n - 2) + 2 - - for _ in 1 ... k { - var x = powmod64(r, d, n) - if x == 1 || x == n - 1 { continue } - - if s == 1 { s = 2 } - - for _ in 1 ... s - 1 { - x = powmod64(x, 2, n) - if x == 1 { return false } - if x == n - 1 { break } - } - - if x != n - 1 { return false } - } - - return true +enum MillerRabinError: Error { + case primeLowAccuracy + case primeLowerBorder + case uIntOverflow } /* - Calculates (base^exp) mod m. - - Inputs: - base: UInt64 { base } - exp: UInt64 { exponent } - m: UInt64 { modulus } - - Outputs: - the result - */ -private func powmod64(_ base: UInt64, _ exp: UInt64, _ m: UInt64) -> UInt64 { - if m == 1 { return 0 } + The Miller–Rabin test relies on an equality or set of equalities that + hold true for prime values, then checks whether or not they hold for + a number that we want to test for primality. + + - Parameter n: an odd integer to be tested for primality; + - Parameter k: a parameter that determines the accuracy of the test + - throws: Can throw an error of type `MillerRabinError`. + - Returns: composite if n is composite, otherwise probably prime +*/ +func checkWithMillerRabin(_ n: UInt, accuracy k: UInt = 1) throws -> Bool { + guard k > 0 else { throw MillerRabinError.primeLowAccuracy } + guard n > 0 else { throw MillerRabinError.primeLowerBorder } + guard n > 3 else { return true } + + // return false for all even numbers bigger than 2 + if n % 2 == 0 { + return false + } - var result: UInt64 = 1 - var b = base % m - var e = exp + let s: UInt = UInt((n - 1).trailingZeroBitCount) + let d: UInt = (n - 1) >> s + + guard UInt(pow(2.0, Double(s))) * d == n - 1 else { throw EncryptionError.primeLowerBorder } + + /// Inspect whether a given witness will reveal the true identity of n. + func tryComposite(_ a: UInt, d: UInt, n: UInt) throws -> Bool? { + var x = try calculateModularExponentiation(base: a, exponent: d, modulus: n) + if x == 1 || x == (n - 1) { + return nil + } + for _ in 1.. 0 { - if e % 2 == 1 { result = mulmod64(result, b, m) } - b = mulmod64(b, b, m) - e >>= 1 - } + for _ in 0.. UInt64 { - var result: UInt64 = 0 - var a = first - var b = second + Calculates the modular exponentiation based on `Applied Cryptography by Bruce Schneier.` + in `Schneier, Bruce (1996). Applied Cryptography: Protocols, Algorithms, + and Source Code in C, Second Edition (2nd ed.). Wiley. ISBN 978-0-471-11709-4.` + + - Parameter base: The natural base b. + - Parameter base: The natural exponent e. + - Parameter base: The natural modulus m. + - Throws: Can throw a `uIntOverflow` if the modulus' square exceeds the memory + limitations of UInt on the current system. + - Returns: The modular exponentiation c. +*/ +private func calculateModularExponentiation(base: UInt, exponent: UInt, modulus: UInt) throws -> UInt { + guard modulus > 1 else { return 0 } + guard !(modulus-1).multipliedReportingOverflow(by: (modulus-1)).overflow else { + throw MillerRabinError.uIntOverflow + } - while a != 0 { - if a % 2 == 1 { result = ((result % m) + (b % m)) % m } // This may overflow if 'm' is a 64bit number && both 'result' and 'b' are very close to but smaller than 'm'. - a >>= 1 - b = (b << 1) % m - } + var result: UInt = 1 + var exponentCopy = exponent + var baseCopy = base % modulus + + while exponentCopy > 0 { + if exponentCopy % 2 == 1 { + result = (result * baseCopy) % modulus + } + exponentCopy = exponentCopy >> 1 + baseCopy = (baseCopy * baseCopy) % modulus + } - return result + return result } diff --git a/Miller-Rabin Primality Test/README.markdown b/Miller-Rabin Primality Test/README.markdown index 07acb9e18..9cc677a2e 100644 --- a/Miller-Rabin Primality Test/README.markdown +++ b/Miller-Rabin Primality Test/README.markdown @@ -27,8 +27,8 @@ The following pseudo code is excerpted from Wikipedia[3]: ## Usage ```swift -mrPrimalityTest(7) // test if 7 is prime. (default iteration = 1) -mrPrimalityTest(7, iteration: 10) // test if 7 is prime && iterate 10 times. +checkWithMillerRabin(7) // test if 7 is prime. (default iteration = 1) +checkWithMillerRabin(7, accuracy: 10) // test if 7 is prime && iterate 10 times. ``` ## Reference @@ -37,6 +37,7 @@ mrPrimalityTest(7, iteration: 10) // test if 7 is prime && iterate 10 time 3. Miller–Rabin primality test - Wikipedia, the free encyclopedia _Written for Swift Algorithm Club by **Sahn Cha**, @scha00_ +_Code updated by **Simon C. Krüger**._ [1]: https://cs.uwaterloo.ca/research/tr/1975/CS-75-27.pdf [2]: http://www.sciencedirect.com/science/article/pii/0022314X80900840 From b47eb3e80afffc20c5e540e33fec66ae7a65bec0 Mon Sep 17 00:00:00 2001 From: laurentaylormarshall <44420971+laurentaylormarshall@users.noreply.github.com> Date: Fri, 26 Oct 2018 18:56:13 -0500 Subject: [PATCH 139/271] Update SlowSort.swift --- Slow Sort/SlowSort.swift | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/Slow Sort/SlowSort.swift b/Slow Sort/SlowSort.swift index c68a53455..813f3b7a9 100644 --- a/Slow Sort/SlowSort.swift +++ b/Slow Sort/SlowSort.swift @@ -5,10 +5,8 @@ // Created by Pope Lukas Schramm (Dabendorf Orthodox Religion) on 16-07-16. // // - -public func slowsort(_ i: Int, _ j: Int, _ numberList: inout [Int]) { - guard i Date: Fri, 26 Oct 2018 19:11:33 -0500 Subject: [PATCH 140/271] Updates function name. --- Slow Sort/SlowSort.swift | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/Slow Sort/SlowSort.swift b/Slow Sort/SlowSort.swift index 813f3b7a9..3b762042a 100644 --- a/Slow Sort/SlowSort.swift +++ b/Slow Sort/SlowSort.swift @@ -1,19 +1,19 @@ // // SlowSort.swift -// +// // // Created by Pope Lukas Schramm (Dabendorf Orthodox Religion) on 16-07-16. // // func slowSort(_ i: Int, _ j: Int, _ numberList: inout [Int]) { - guard if i < j else { return } - let m = (i+j)/2 - slowsort(i, m, &numberList) - slowsort(m+1, j, &numberList) - if numberList[j] < numberList[m] { - let temp = numberList[j] - numberList[j] = numberList[m] - numberList[m] = temp - } - slowsort(i, j-1, &numberList) + guard if i < j else { return } + let m = (i+j)/2 + slowSort(i, m, &numberList) + slowSort(m+1, j, &numberList) + if numberList[j] < numberList[m] { + let temp = numberList[j] + numberList[j] = numberList[m] + numberList[m] = temp + } + slowSort(i, j-1, &numberList) } From 22efd0d33aa9d3bfacf3c84701dc157bb10e5aa7 Mon Sep 17 00:00:00 2001 From: Erik Strottmann Date: Sat, 27 Oct 2018 10:26:54 -0700 Subject: [PATCH 141/271] Standardize Trie indentation to 2 spaces 2 spaces is recommended by the Ray Wenderlich Swift Style Guide. --- Trie/ReadMe.md | 40 +-- Trie/Trie/Trie.xcodeproj/project.pbxproj | 2 + Trie/Trie/Trie/AppDelegate.swift | 12 +- Trie/Trie/Trie/Trie.swift | 118 ++++---- Trie/Trie/Trie/ViewController.swift | 16 +- Trie/Trie/TrieTests/TrieTests.swift | 340 +++++++++++------------ Trie/Trie/TrieUITests/TrieUITests.swift | 34 +-- 7 files changed, 280 insertions(+), 282 deletions(-) diff --git a/Trie/ReadMe.md b/Trie/ReadMe.md index 8e473a619..8d0c45c8a 100644 --- a/Trie/ReadMe.md +++ b/Trie/ReadMe.md @@ -27,29 +27,29 @@ Tries are very useful for certain situations. Here are some of the advantages: ```swift func contains(word: String) -> Bool { - guard !word.isEmpty else { return false } + guard !word.isEmpty else { return false } - // 1 - var currentNode = root + // 1 + var currentNode = root - // 2 - var characters = Array(word.lowercased()) - var currentIndex = 0 + // 2 + var characters = Array(word.lowercased()) + var currentIndex = 0 - // 3 - while currentIndex < characters.count, - let child = currentNode.children[characters[currentIndex]] { - - currentNode = child - currentIndex += 1 - } - - // 4 - if currentIndex == characters.count && currentNode.isTerminating { - return true - } else { - return false - } + // 3 + while currentIndex < characters.count, + let child = currentNode.children[characters[currentIndex]] { + + currentNode = child + currentIndex += 1 + } + + // 4 + if currentIndex == characters.count && currentNode.isTerminating { + return true + } else { + return false + } } ``` diff --git a/Trie/Trie/Trie.xcodeproj/project.pbxproj b/Trie/Trie/Trie.xcodeproj/project.pbxproj index 1e3602eea..6b7cc9b61 100644 --- a/Trie/Trie/Trie.xcodeproj/project.pbxproj +++ b/Trie/Trie/Trie.xcodeproj/project.pbxproj @@ -87,7 +87,9 @@ EB798E191DFEF79900F0628D /* TrieUITests */, EB798DFB1DFEF79900F0628D /* Products */, ); + indentWidth = 2; sourceTree = ""; + tabWidth = 2; }; EB798DFB1DFEF79900F0628D /* Products */ = { isa = PBXGroup; diff --git a/Trie/Trie/Trie/AppDelegate.swift b/Trie/Trie/Trie/AppDelegate.swift index b2c46695b..48dc24673 100644 --- a/Trie/Trie/Trie/AppDelegate.swift +++ b/Trie/Trie/Trie/AppDelegate.swift @@ -11,12 +11,12 @@ import Cocoa @NSApplicationMain class AppDelegate: NSObject, NSApplicationDelegate { - func applicationDidFinishLaunching(_ aNotification: Notification) { - // Insert code here to initialize your application - } + func applicationDidFinishLaunching(_ aNotification: Notification) { + // Insert code here to initialize your application + } - func applicationWillTerminate(_ aNotification: Notification) { - // Insert code here to tear down your application - } + func applicationWillTerminate(_ aNotification: Notification) { + // Insert code here to tear down your application + } } diff --git a/Trie/Trie/Trie/Trie.swift b/Trie/Trie/Trie/Trie.swift index fbc933138..accc7b61c 100644 --- a/Trie/Trie/Trie/Trie.swift +++ b/Trie/Trie/Trie/Trie.swift @@ -43,54 +43,53 @@ class TrieNode { /// A trie data structure containing words. Each node is a single /// character of a word. class Trie: NSObject, NSCoding { - typealias Node = TrieNode - /// The number of words in the trie - public var count: Int { - return wordCount - } - /// Is the trie empty? - public var isEmpty: Bool { - return wordCount == 0 - } - /// All words currently in the trie - public var words: [String] { - return wordsInSubtrie(rootNode: root, partialWord: "") - } - fileprivate let root: Node - fileprivate var wordCount: Int - - /// Creates an empty trie. - override init() { - root = Node() - wordCount = 0 - super.init() - } + typealias Node = TrieNode + /// The number of words in the trie + public var count: Int { + return wordCount + } + /// Is the trie empty? + public var isEmpty: Bool { + return wordCount == 0 + } + /// All words currently in the trie + public var words: [String] { + return wordsInSubtrie(rootNode: root, partialWord: "") + } + fileprivate let root: Node + fileprivate var wordCount: Int + + /// Creates an empty trie. + override init() { + root = Node() + wordCount = 0 + super.init() + } - // MARK: NSCoding + // MARK: NSCoding - /// Initializes the trie with words from an archive - /// - /// - Parameter decoder: Decodes the archive - required convenience init?(coder decoder: NSCoder) { - self.init() - let words = decoder.decodeObject(forKey: "words") as? [String] - for word in words! { - self.insert(word: word) - } + /// Initializes the trie with words from an archive + /// + /// - Parameter decoder: Decodes the archive + required convenience init?(coder decoder: NSCoder) { + self.init() + let words = decoder.decodeObject(forKey: "words") as? [String] + for word in words! { + self.insert(word: word) } + } - /// Encodes the words in the trie by putting them in an array then encoding - /// the array. - /// - /// - Parameter coder: The object that will encode the array - func encode(with coder: NSCoder) { - coder.encode(self.words, forKey: "words") - } + /// Encodes the words in the trie by putting them in an array then encoding + /// the array. + /// + /// - Parameter coder: The object that will encode the array + func encode(with coder: NSCoder) { + coder.encode(self.words, forKey: "words") + } } // MARK: - Adds methods: insert, remove, contains extension Trie { - /// Inserts a word into the trie. If the word is already present, /// there is no change. /// @@ -142,14 +141,14 @@ extension Trie { /// - Returns: the node where the search ended, nil if the /// search failed. private func findLastNodeOf(word: String) -> Node? { - var currentNode = root - for character in word.lowercased() { - guard let childNode = currentNode.children[character] else { - return nil - } - currentNode = childNode + var currentNode = root + for character in word.lowercased() { + guard let childNode = currentNode.children[character] else { + return nil } - return currentNode + currentNode = childNode + } + return currentNode } /// Attempts to walk to the terminating node of a word. The @@ -160,10 +159,9 @@ extension Trie { /// search failed. private func findTerminalNodeOf(word: String) -> Node? { if let lastNode = findLastNodeOf(word: word) { - return lastNode.isTerminating ? lastNode : nil + return lastNode.isTerminating ? lastNode : nil } return nil - } /// Deletes a word from the trie by starting with the last letter @@ -237,17 +235,17 @@ extension Trie { /// - prefix: the letters for word prefix /// - Returns: the words in the subtrie that start with prefix func findWordsWithPrefix(prefix: String) -> [String] { - var words = [String]() - let prefixLowerCased = prefix.lowercased() - if let lastNode = findLastNodeOf(word: prefixLowerCased) { - if lastNode.isTerminating { - words.append(prefixLowerCased) - } - for childNode in lastNode.children.values { - let childWords = wordsInSubtrie(rootNode: childNode, partialWord: prefixLowerCased) - words += childWords - } + var words = [String]() + let prefixLowerCased = prefix.lowercased() + if let lastNode = findLastNodeOf(word: prefixLowerCased) { + if lastNode.isTerminating { + words.append(prefixLowerCased) + } + for childNode in lastNode.children.values { + let childWords = wordsInSubtrie(rootNode: childNode, partialWord: prefixLowerCased) + words += childWords } - return words + } + return words } } diff --git a/Trie/Trie/Trie/ViewController.swift b/Trie/Trie/Trie/ViewController.swift index 928b01f4c..8ce34f6c7 100644 --- a/Trie/Trie/Trie/ViewController.swift +++ b/Trie/Trie/Trie/ViewController.swift @@ -10,16 +10,16 @@ import Cocoa class ViewController: NSViewController { - override func viewDidLoad() { - super.viewDidLoad() + override func viewDidLoad() { + super.viewDidLoad() - // Do any additional setup after loading the view. - } + // Do any additional setup after loading the view. + } - override var representedObject: Any? { - didSet { - // Update the view, if already loaded. - } + override var representedObject: Any? { + didSet { + // Update the view, if already loaded. } + } } diff --git a/Trie/Trie/TrieTests/TrieTests.swift b/Trie/Trie/TrieTests/TrieTests.swift index b69c5666e..0c5bc69c6 100644 --- a/Trie/Trie/TrieTests/TrieTests.swift +++ b/Trie/Trie/TrieTests/TrieTests.swift @@ -10,186 +10,184 @@ import XCTest @testable import Trie class TrieTests: XCTestCase { - var wordArray: [String]? - var trie = Trie() - - /// Makes sure that the wordArray and trie are initialized before each test. - override func setUp() { - super.setUp() - createWordArray() - insertWordsIntoTrie() + var wordArray: [String]? + var trie = Trie() + + /// Makes sure that the wordArray and trie are initialized before each test. + override func setUp() { + super.setUp() + createWordArray() + insertWordsIntoTrie() + } + + /// Don't need to do anything here because the wordArray and trie should + /// stay around. + override func tearDown() { + super.tearDown() + } + + /// Reads words from the dictionary file and inserts them into an array. If + /// the word array already has words, do nothing. This allows running all + /// tests without repeatedly filling the array with the same values. + func createWordArray() { + guard wordArray == nil else { + return } - - /// Don't need to do anything here because the wordArray and trie should - /// stay around. - override func tearDown() { - super.tearDown() - } - - /// Reads words from the dictionary file and inserts them into an array. If - /// the word array already has words, do nothing. This allows running all - /// tests without repeatedly filling the array with the same values. - func createWordArray() { - guard wordArray == nil else { - return - } - let resourcePath = Bundle.main.resourcePath! as NSString - let fileName = "dictionary.txt" - let filePath = resourcePath.appendingPathComponent(fileName) - - var data: String? - do { - data = try String(contentsOfFile: filePath, encoding: String.Encoding.utf8) - } catch let error as NSError { - XCTAssertNil(error) - } - XCTAssertNotNil(data) - let dictionarySize = 162825 - wordArray = data!.components(separatedBy: "\n") - XCTAssertEqual(wordArray!.count, dictionarySize) - } - - /// Inserts words into a trie. If the trie is non-empty, don't do anything. - func insertWordsIntoTrie() { - guard let wordArray = wordArray, trie.count == 0 else { return } - for word in wordArray { - trie.insert(word: word) - } - } - - /// Tests that a newly created trie has zero words. - func testCreate() { - let trie = Trie() - XCTAssertEqual(trie.count, 0) - } - - /// Tests the insert method - func testInsert() { - let trie = Trie() - trie.insert(word: "cute") - trie.insert(word: "cutie") - trie.insert(word: "fred") - XCTAssertTrue(trie.contains(word: "cute")) - XCTAssertFalse(trie.contains(word: "cut")) - trie.insert(word: "cut") - XCTAssertTrue(trie.contains(word: "cut")) - XCTAssertEqual(trie.count, 4) - } - - /// Tests the remove method - func testRemove() { - let trie = Trie() - trie.insert(word: "cute") - trie.insert(word: "cut") - XCTAssertEqual(trie.count, 2) - trie.remove(word: "cute") - XCTAssertTrue(trie.contains(word: "cut")) - XCTAssertFalse(trie.contains(word: "cute")) - XCTAssertEqual(trie.count, 1) + let resourcePath = Bundle.main.resourcePath! as NSString + let fileName = "dictionary.txt" + let filePath = resourcePath.appendingPathComponent(fileName) + + var data: String? + do { + data = try String(contentsOfFile: filePath, encoding: String.Encoding.utf8) + } catch let error as NSError { + XCTAssertNil(error) } - - /// Tests the words property - func testWords() { - let trie = Trie() - var words = trie.words - XCTAssertEqual(words.count, 0) - trie.insert(word: "foobar") - words = trie.words - XCTAssertEqual(words[0], "foobar") - XCTAssertEqual(words.count, 1) + XCTAssertNotNil(data) + let dictionarySize = 162825 + wordArray = data!.components(separatedBy: "\n") + XCTAssertEqual(wordArray!.count, dictionarySize) + } + + /// Inserts words into a trie. If the trie is non-empty, don't do anything. + func insertWordsIntoTrie() { + guard let wordArray = wordArray, trie.count == 0 else { return } + for word in wordArray { + trie.insert(word: word) } - - /// Tests the performance of the insert method. - func testInsertPerformance() { - self.measure { - let trie = Trie() - for word in self.wordArray! { - trie.insert(word: word) - } - } - XCTAssertGreaterThan(trie.count, 0) - XCTAssertEqual(trie.count, wordArray?.count) + } + + /// Tests that a newly created trie has zero words. + func testCreate() { + let trie = Trie() + XCTAssertEqual(trie.count, 0) + } + + /// Tests the insert method + func testInsert() { + let trie = Trie() + trie.insert(word: "cute") + trie.insert(word: "cutie") + trie.insert(word: "fred") + XCTAssertTrue(trie.contains(word: "cute")) + XCTAssertFalse(trie.contains(word: "cut")) + trie.insert(word: "cut") + XCTAssertTrue(trie.contains(word: "cut")) + XCTAssertEqual(trie.count, 4) + } + + /// Tests the remove method + func testRemove() { + let trie = Trie() + trie.insert(word: "cute") + trie.insert(word: "cut") + XCTAssertEqual(trie.count, 2) + trie.remove(word: "cute") + XCTAssertTrue(trie.contains(word: "cut")) + XCTAssertFalse(trie.contains(word: "cute")) + XCTAssertEqual(trie.count, 1) + } + + /// Tests the words property + func testWords() { + let trie = Trie() + var words = trie.words + XCTAssertEqual(words.count, 0) + trie.insert(word: "foobar") + words = trie.words + XCTAssertEqual(words[0], "foobar") + XCTAssertEqual(words.count, 1) + } + + /// Tests the performance of the insert method. + func testInsertPerformance() { + self.measure { + let trie = Trie() + for word in self.wordArray! { + trie.insert(word: word) + } } - - /// Tests the performance of the insert method when the words are already - /// present. - func testInsertAgainPerformance() { - self.measure { - for word in self.wordArray! { - self.trie.insert(word: word) - } - } + XCTAssertGreaterThan(trie.count, 0) + XCTAssertEqual(trie.count, wordArray?.count) + } + + /// Tests the performance of the insert method when the words are already + /// present. + func testInsertAgainPerformance() { + self.measure { + for word in self.wordArray! { + self.trie.insert(word: word) + } } - - /// Tests the performance of the contains method. - func testContainsPerformance() { - self.measure { - for word in self.wordArray! { - XCTAssertTrue(self.trie.contains(word: word)) - } - } + } + + /// Tests the performance of the contains method. + func testContainsPerformance() { + self.measure { + for word in self.wordArray! { + XCTAssertTrue(self.trie.contains(word: word)) + } } + } - /// Tests the performance of the remove method. Since setup has already put - /// words into the trie, remove them before measuring performance. - func testRemovePerformance() { - for word in self.wordArray! { - self.trie.remove(word: word) - } - self.measure { - self.insertWordsIntoTrie() - for word in self.wordArray! { - self.trie.remove(word: word) - } - } - XCTAssertEqual(trie.count, 0) + /// Tests the performance of the remove method. Since setup has already put + /// words into the trie, remove them before measuring performance. + func testRemovePerformance() { + for word in self.wordArray! { + self.trie.remove(word: word) } - - /// Tests the performance of the words computed property. Also tests to see - /// if it worked properly. - func testWordsPerformance() { - var words: [String]? - self.measure { - words = self.trie.words - } - XCTAssertEqual(words?.count, trie.count) - for word in words! { - XCTAssertTrue(self.trie.contains(word: word)) - } + self.measure { + self.insertWordsIntoTrie() + for word in self.wordArray! { + self.trie.remove(word: word) + } } - - /// Tests the archiving and unarchiving of the trie. - func testArchiveAndUnarchive() { - let resourcePath = Bundle.main.resourcePath! as NSString - let fileName = "dictionary-archive" - let filePath = resourcePath.appendingPathComponent(fileName) - NSKeyedArchiver.archiveRootObject(trie, toFile: filePath) - let trieCopy = NSKeyedUnarchiver.unarchiveObject(withFile: filePath) as? Trie - XCTAssertEqual(trieCopy?.count, trie.count) - + XCTAssertEqual(trie.count, 0) + } + + /// Tests the performance of the words computed property. Also tests to see + /// if it worked properly. + func testWordsPerformance() { + var words: [String]? + self.measure { + words = self.trie.words } - - func testFindWordsWithPrefix() { - let trie = Trie() - trie.insert(word: "test") - trie.insert(word: "another") - trie.insert(word: "exam") - let wordsAll = trie.findWordsWithPrefix(prefix: "") - XCTAssertEqual(wordsAll.sorted(), ["another", "exam", "test"]) - let words = trie.findWordsWithPrefix(prefix: "ex") - XCTAssertEqual(words, ["exam"]) - trie.insert(word: "examination") - let words2 = trie.findWordsWithPrefix(prefix: "exam") - XCTAssertEqual(words2, ["exam", "examination"]) - let noWords = trie.findWordsWithPrefix(prefix: "tee") - XCTAssertEqual(noWords, []) - let unicodeWord = "😬😎" - trie.insert(word: unicodeWord) - let wordsUnicode = trie.findWordsWithPrefix(prefix: "😬") - XCTAssertEqual(wordsUnicode, [unicodeWord]) - trie.insert(word: "Team") - let wordsUpperCase = trie.findWordsWithPrefix(prefix: "Te") - XCTAssertEqual(wordsUpperCase.sorted(), ["team", "test"]) - + XCTAssertEqual(words?.count, trie.count) + for word in words! { + XCTAssertTrue(self.trie.contains(word: word)) } + } + + /// Tests the archiving and unarchiving of the trie. + func testArchiveAndUnarchive() { + let resourcePath = Bundle.main.resourcePath! as NSString + let fileName = "dictionary-archive" + let filePath = resourcePath.appendingPathComponent(fileName) + NSKeyedArchiver.archiveRootObject(trie, toFile: filePath) + let trieCopy = NSKeyedUnarchiver.unarchiveObject(withFile: filePath) as? Trie + XCTAssertEqual(trieCopy?.count, trie.count) + } + + func testFindWordsWithPrefix() { + let trie = Trie() + trie.insert(word: "test") + trie.insert(word: "another") + trie.insert(word: "exam") + let wordsAll = trie.findWordsWithPrefix(prefix: "") + XCTAssertEqual(wordsAll.sorted(), ["another", "exam", "test"]) + let words = trie.findWordsWithPrefix(prefix: "ex") + XCTAssertEqual(words, ["exam"]) + trie.insert(word: "examination") + let words2 = trie.findWordsWithPrefix(prefix: "exam") + XCTAssertEqual(words2, ["exam", "examination"]) + let noWords = trie.findWordsWithPrefix(prefix: "tee") + XCTAssertEqual(noWords, []) + let unicodeWord = "😬😎" + trie.insert(word: unicodeWord) + let wordsUnicode = trie.findWordsWithPrefix(prefix: "😬") + XCTAssertEqual(wordsUnicode, [unicodeWord]) + trie.insert(word: "Team") + let wordsUpperCase = trie.findWordsWithPrefix(prefix: "Te") + XCTAssertEqual(wordsUpperCase.sorted(), ["team", "test"]) + } } diff --git a/Trie/Trie/TrieUITests/TrieUITests.swift b/Trie/Trie/TrieUITests/TrieUITests.swift index acb3b1756..380bf3092 100644 --- a/Trie/Trie/TrieUITests/TrieUITests.swift +++ b/Trie/Trie/TrieUITests/TrieUITests.swift @@ -10,27 +10,27 @@ import XCTest class TrieUITests: XCTestCase { - override func setUp() { - super.setUp() + override func setUp() { + super.setUp() - // Put setup code here. This method is called before the invocation of each test method in the class. + // Put setup code here. This method is called before the invocation of each test method in the class. - // In UI tests it is usually best to stop immediately when a failure occurs. - continueAfterFailure = false - // UI tests must launch the application that they test. Doing this in setup will make sure it happens for each test method. - XCUIApplication().launch() + // In UI tests it is usually best to stop immediately when a failure occurs. + continueAfterFailure = false + // UI tests must launch the application that they test. Doing this in setup will make sure it happens for each test method. + XCUIApplication().launch() - // In UI tests it’s important to set the initial state - such as interface orientation - required for your tests before they run. The setUp method is a good place to do this. - } + // In UI tests it’s important to set the initial state - such as interface orientation - required for your tests before they run. The setUp method is a good place to do this. + } - override func tearDown() { - // Put teardown code here. This method is called after the invocation of each test method in the class. - super.tearDown() - } + override func tearDown() { + // Put teardown code here. This method is called after the invocation of each test method in the class. + super.tearDown() + } - func testExample() { - // Use recording to get started writing UI tests. - // Use XCTAssert and related functions to verify your tests produce the correct results. - } + func testExample() { + // Use recording to get started writing UI tests. + // Use XCTAssert and related functions to verify your tests produce the correct results. + } } From 41eb9c1ee1591472c24b49108295261f698a3f1b Mon Sep 17 00:00:00 2001 From: Samwel Charles Date: Mon, 29 Oct 2018 00:22:43 +0300 Subject: [PATCH 142/271] update union-find to swift 4.2 --- Union-Find/UnionFind.playground/Contents.swift | 5 ----- .../xcshareddata/IDEWorkspaceChecks.plist | 8 ++++++++ 2 files changed, 8 insertions(+), 5 deletions(-) create mode 100644 Union-Find/UnionFind.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist diff --git a/Union-Find/UnionFind.playground/Contents.swift b/Union-Find/UnionFind.playground/Contents.swift index 6ac3b4c4e..b1f7fb4e1 100644 --- a/Union-Find/UnionFind.playground/Contents.swift +++ b/Union-Find/UnionFind.playground/Contents.swift @@ -1,10 +1,5 @@ //: Playground - noun: a place where people can play -// last checked with Xcode 9.0b4 -#if swift(>=4.0) -print("Hello, Swift 4!") -#endif - var dsu = UnionFindQuickUnion() for i in 1...10 { diff --git a/Union-Find/UnionFind.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Union-Find/UnionFind.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/Union-Find/UnionFind.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + From cb76b97e3f295d171267044ca599d27db113a7ee Mon Sep 17 00:00:00 2001 From: Samwel Charles Date: Mon, 29 Oct 2018 01:01:09 +0300 Subject: [PATCH 143/271] add link to merge sort algorithm in buble sort algorith README.md file --- Bubble Sort/README.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Bubble Sort/README.markdown b/Bubble Sort/README.markdown index e55129d93..c4b2c37c8 100644 --- a/Bubble Sort/README.markdown +++ b/Bubble Sort/README.markdown @@ -117,7 +117,7 @@ There is no Fifth pass #### Conclusion -Even with the proposed optimizations, this is still a terribly inefficient sorting algorithm. A good alternative is [Merge Sort](), that not only is better performing, has a similar degree of dificulty to implement. +Even with the proposed optimizations, this is still a terribly inefficient sorting algorithm. A good alternative is [Merge Sort](https://github.com/raywenderlich/swift-algorithm-club/tree/master/Merge%20Sort), that not only is better performing, has a similar degree of dificulty to implement. *Updated for the Swift Algorithm Club by Julio Brazil* From 299a67caeb984577561aaf1921271015558bfd6e Mon Sep 17 00:00:00 2001 From: Julio Brazil Date: Mon, 29 Oct 2018 11:45:21 -0300 Subject: [PATCH 144/271] addition of convenience method --- Bubble Sort/MyPlayground.playground/Contents.swift | 4 +++- .../MyPlayground.playground/Sources/BubbleSort.swift | 10 +++++++--- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/Bubble Sort/MyPlayground.playground/Contents.swift b/Bubble Sort/MyPlayground.playground/Contents.swift index 8d27d801e..6188a0763 100644 --- a/Bubble Sort/MyPlayground.playground/Contents.swift +++ b/Bubble Sort/MyPlayground.playground/Contents.swift @@ -3,4 +3,6 @@ import Foundation var array = [4,2,1,3] print("before:",array) -print("after:",BubbleSort(array)) +print("after:", bubbleSort(array)) +print("after:", bubbleSort(array, <)) +print("after:", bubbleSort(array, >)) diff --git a/Bubble Sort/MyPlayground.playground/Sources/BubbleSort.swift b/Bubble Sort/MyPlayground.playground/Sources/BubbleSort.swift index 9c091b661..09e01542b 100644 --- a/Bubble Sort/MyPlayground.playground/Sources/BubbleSort.swift +++ b/Bubble Sort/MyPlayground.playground/Sources/BubbleSort.swift @@ -23,14 +23,18 @@ import Foundation /// Performs the bubble sort algorithm in the array /// -/// - Parameter elements: the array to be sorted +/// - Parameter elements: a array of elements that implement the Comparable protocol /// - Returns: an array with the same elements but in order -public func BubbleSort (_ elements: [T]) -> [T] where T: Comparable { +public func bubbleSort (_ elements: [T]) -> [T] where T: Comparable { + return bubbleSort(elements, <) +} + +public func bubbleSort (_ elements: [T], _ comparison: (T,T) -> Bool) -> [T] { var array = elements for i in 0.. Date: Tue, 30 Oct 2018 10:11:48 +0100 Subject: [PATCH 145/271] Removing unnecessary Error case for empty list * Was intended to be a second example, but is not yet implemented --- GCD/GCD.playground/Contents.swift | 1 - 1 file changed, 1 deletion(-) diff --git a/GCD/GCD.playground/Contents.swift b/GCD/GCD.playground/Contents.swift index 9dfd7cca9..175d26639 100644 --- a/GCD/GCD.playground/Contents.swift +++ b/GCD/GCD.playground/Contents.swift @@ -106,7 +106,6 @@ func findEasySolution(_ m: Int, _ n: Int) -> Int? { enum LCMError: Error { case divisionByZero - case lcmEmptyList } /* From 34a6067355c2596754500ad309eb79bf540f135c Mon Sep 17 00:00:00 2001 From: cr0ss Date: Tue, 30 Oct 2018 10:12:34 +0100 Subject: [PATCH 146/271] Also removes the lcmEmptyList from the actual code file --- GCD/GCD.swift | 1 - 1 file changed, 1 deletion(-) diff --git a/GCD/GCD.swift b/GCD/GCD.swift index 85b7681f0..f4b390e63 100644 --- a/GCD/GCD.swift +++ b/GCD/GCD.swift @@ -105,7 +105,6 @@ func findEasySolution(_ m: Int, _ n: Int) -> Int? { enum LCMError: Error { case divisionByZero - case lcmEmptyList } /* From 1e8e231d3cceb8d57a5bdf6838b4f8b544cdfe65 Mon Sep 17 00:00:00 2001 From: Randy the Dev <37282011+RandyTheDev@users.noreply.github.com> Date: Thu, 1 Nov 2018 06:55:11 +1100 Subject: [PATCH 147/271] Updated Run-Length Encoding to Swift 4.2 --- Run-Length Encoding/RLE.playground/Contents.swift | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/Run-Length Encoding/RLE.playground/Contents.swift b/Run-Length Encoding/RLE.playground/Contents.swift index fc2d82505..8d6a0a403 100644 --- a/Run-Length Encoding/RLE.playground/Contents.swift +++ b/Run-Length Encoding/RLE.playground/Contents.swift @@ -1,10 +1,5 @@ //: Playground - noun: a place where people can play -// last checked with Xcode 9.0b4 -#if swift(>=4.0) -print("Hello, Swift 4!") -#endif - import Foundation let originalString = "aaaaabbbcdeeeeeeef" @@ -64,7 +59,7 @@ func testBufferWithoutSpans() -> Bool { // data ends up being longer. var bytes: [UInt8] = [] for i in 0..<1024 { - bytes.append(UInt8(i%256)) + bytes.append(UInt8(i % 256)) } return encodeAndDecode(bytes) } From d454cf1e1b3a9b60bc005a8b3051be1d328d1932 Mon Sep 17 00:00:00 2001 From: Randy the Dev <37282011+RandyTheDev@users.noreply.github.com> Date: Thu, 1 Nov 2018 07:25:19 +1100 Subject: [PATCH 148/271] Confirmed Linear Regression to work with Swift 4.2 --- .../LinearRegression.playground/Contents.swift | 7 +------ Linear Regression/README.markdown | 2 +- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/Linear Regression/LinearRegression.playground/Contents.swift b/Linear Regression/LinearRegression.playground/Contents.swift index 3e4135794..a093ef566 100644 --- a/Linear Regression/LinearRegression.playground/Contents.swift +++ b/Linear Regression/LinearRegression.playground/Contents.swift @@ -2,11 +2,6 @@ import Foundation -// last checked with Xcode 4.0b4 -#if swift(>=4.0) -print("Hello, Swift 4!") -#endif - let carAge: [Double] = [10, 8, 3, 3, 2, 1] let carPrice: [Double] = [500, 400, 7000, 8500, 11000, 10500] var intercept = 0.0 @@ -22,7 +17,7 @@ let numberOfCarAdvertsWeSaw = carPrice.count let numberOfIterations = 100 let alpha = 0.0001 -for n in 1...numberOfIterations { +for _ in 1...numberOfIterations { for i in 0.. Date: Thu, 1 Nov 2018 07:35:17 +1100 Subject: [PATCH 149/271] Updated Minimum Edit Distance Playground for Swift 4.2 --- .../MinimumEditDistance.playground/Contents.swift | 12 ++++-------- Minimum Edit Distance/README.markdown | 4 ++-- 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/Minimum Edit Distance/MinimumEditDistance.playground/Contents.swift b/Minimum Edit Distance/MinimumEditDistance.playground/Contents.swift index 967e73182..5db0aeb0d 100644 --- a/Minimum Edit Distance/MinimumEditDistance.playground/Contents.swift +++ b/Minimum Edit Distance/MinimumEditDistance.playground/Contents.swift @@ -1,15 +1,11 @@ // Minimum Edit Distance -// last checked with Xcode 9.0b4 -#if swift(>=4.0) -print("Hello, Swift 4!") -#endif extension String { public func minimumEditDistance(other: String) -> Int { - let m = self.characters.count - let n = other.characters.count + let m = self.count + let n = other.count var matrix = [[Int]](repeating: [Int](repeating: 0, count: n + 1), count: m + 1) // initialize matrix @@ -24,8 +20,8 @@ extension String { } // compute Levenshtein distance - for (i, selfChar) in self.characters.enumerated() { - for (j, otherChar) in other.characters.enumerated() { + for (i, selfChar) in self.enumerated() { + for (j, otherChar) in other.enumerated() { if otherChar == selfChar { // substitution of equal symbols with cost 0 matrix[i + 1][j + 1] = matrix[i][j] diff --git a/Minimum Edit Distance/README.markdown b/Minimum Edit Distance/README.markdown index b8880b2d4..c8e5e2f6d 100755 --- a/Minimum Edit Distance/README.markdown +++ b/Minimum Edit Distance/README.markdown @@ -37,8 +37,8 @@ Then in each cell the minimum of the cost of insertion, deletion, or substitutio ```swift // compute Levenshtein distance -for (i, selfChar) in self.characters.enumerated() { - for (j, otherChar) in other.characters.enumerated() { +for (i, selfChar) in self.enumerated() { + for (j, otherChar) in other.enumerated() { if otherChar == selfChar { // substitution of equal symbols with cost 0 matrix[i + 1][j + 1] = matrix[i][j] From eea4cfc6eaba53d86c3a383b1dce9c3c374b3ebd Mon Sep 17 00:00:00 2001 From: iillx Date: Wed, 31 Oct 2018 22:56:29 -0300 Subject: [PATCH 150/271] Counting Sort working with Swift 4.2 --- Counting Sort/CountingSort.playground/Contents.swift | 5 ----- 1 file changed, 5 deletions(-) diff --git a/Counting Sort/CountingSort.playground/Contents.swift b/Counting Sort/CountingSort.playground/Contents.swift index 4d918e384..dc375512a 100644 --- a/Counting Sort/CountingSort.playground/Contents.swift +++ b/Counting Sort/CountingSort.playground/Contents.swift @@ -1,10 +1,5 @@ //: Playground - noun: a place where people can play -// last checked with Xcode 9.0b4 -#if swift(>=4.0) -print("Hello, Swift 4!") -#endif - enum CountingSortError: Error { case arrayEmpty } From 43e76adfc53c5cadde2511e9fc80fa3c59114be9 Mon Sep 17 00:00:00 2001 From: iillx Date: Wed, 31 Oct 2018 23:10:55 -0300 Subject: [PATCH 151/271] Union Find working with Swift 4.2 and Xcode 10 --- Union-Find/UnionFind.playground/Contents.swift | 5 ----- 1 file changed, 5 deletions(-) diff --git a/Union-Find/UnionFind.playground/Contents.swift b/Union-Find/UnionFind.playground/Contents.swift index 6ac3b4c4e..b1f7fb4e1 100644 --- a/Union-Find/UnionFind.playground/Contents.swift +++ b/Union-Find/UnionFind.playground/Contents.swift @@ -1,10 +1,5 @@ //: Playground - noun: a place where people can play -// last checked with Xcode 9.0b4 -#if swift(>=4.0) -print("Hello, Swift 4!") -#endif - var dsu = UnionFindQuickUnion() for i in 1...10 { From 6707ce26934addaceff3d54ee417632e210443df Mon Sep 17 00:00:00 2001 From: iillx Date: Wed, 31 Oct 2018 23:16:04 -0300 Subject: [PATCH 152/271] Shunting Yard working fine with Swift 4.2 and Xcode 10 --- Shunting Yard/ShuntingYard.playground/Contents.swift | 5 ----- .../xcshareddata/IDEWorkspaceChecks.plist | 8 ++++++++ 2 files changed, 8 insertions(+), 5 deletions(-) create mode 100644 Shunting Yard/ShuntingYard.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist diff --git a/Shunting Yard/ShuntingYard.playground/Contents.swift b/Shunting Yard/ShuntingYard.playground/Contents.swift index ddd73de59..38431f5e2 100644 --- a/Shunting Yard/ShuntingYard.playground/Contents.swift +++ b/Shunting Yard/ShuntingYard.playground/Contents.swift @@ -1,10 +1,5 @@ //: Playground - noun: a place where people can play -// last checked with Xcode 9.0b4 -#if swift(>=4.0) -print("Hello, Swift 4!") -#endif - internal enum OperatorAssociativity { case leftAssociative case rightAssociative diff --git a/Shunting Yard/ShuntingYard.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Shunting Yard/ShuntingYard.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/Shunting Yard/ShuntingYard.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + From a1d65fcba404f8a59897c46480e54cadbe491b63 Mon Sep 17 00:00:00 2001 From: iillx Date: Wed, 31 Oct 2018 23:25:54 -0300 Subject: [PATCH 153/271] Updated random number generation to Swift 4.2 --- Set Cover (Unweighted)/SetCover.playground/Contents.swift | 7 ++----- .../SetCover.playground/Sources/RandomArrayOfSets.swift | 4 ++-- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/Set Cover (Unweighted)/SetCover.playground/Contents.swift b/Set Cover (Unweighted)/SetCover.playground/Contents.swift index d61b9c84a..065f5fd4d 100644 --- a/Set Cover (Unweighted)/SetCover.playground/Contents.swift +++ b/Set Cover (Unweighted)/SetCover.playground/Contents.swift @@ -1,10 +1,5 @@ // SetCover -// last checked with Xcode 9.0b4 -#if swift(>=4.0) -print("Hello, Swift 4!") -#endif - let universe1 = Set(1...7) let array1 = randomArrayOfSets(covering: universe1) let cover1 = universe1.cover(within: array1) @@ -36,3 +31,5 @@ let emptySet = Set() let coverTest1 = emptySet.cover(within: array1) let coverTest2 = universe1.cover(within: Array>()) let coverTest3 = emptySet.cover(within: Array>()) + + diff --git a/Set Cover (Unweighted)/SetCover.playground/Sources/RandomArrayOfSets.swift b/Set Cover (Unweighted)/SetCover.playground/Sources/RandomArrayOfSets.swift index 9454c6383..ac4ff063e 100644 --- a/Set Cover (Unweighted)/SetCover.playground/Sources/RandomArrayOfSets.swift +++ b/Set Cover (Unweighted)/SetCover.playground/Sources/RandomArrayOfSets.swift @@ -14,10 +14,10 @@ public func randomArrayOfSets(covering universe: Set, while true { var generatedSet = Set() - let targetSetSize = Int(arc4random_uniform(UInt32(maxSetSize)) + 1) + let targetSetSize = Int.random(in: 0...maxSetSize) + 1 while true { - let randomUniverseIndex = Int(arc4random_uniform(UInt32(universe.count))) + let randomUniverseIndex = Int.random(in: 0...universe.count) for (setIndex, value) in universe.enumerated() { if setIndex == randomUniverseIndex { generatedSet.insert(value) From f37fb19f054c95b654e07186d5f6fc5cf56bb12d Mon Sep 17 00:00:00 2001 From: Bruno Scheele Date: Thu, 1 Nov 2018 20:55:17 +0100 Subject: [PATCH 154/271] Update README according to comments. --- Bloom Filter/README.markdown | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Bloom Filter/README.markdown b/Bloom Filter/README.markdown index 4364db857..5f2ede069 100644 --- a/Bloom Filter/README.markdown +++ b/Bloom Filter/README.markdown @@ -102,7 +102,9 @@ If you're coming from another imperative language, you might notice the unusual ## Another approach -Another approach to create different hashes of an element for use in the Bloom filter, is to use the same hash function for every iteration, but combine it with different random numbers. This can help, because finding good hashing functions is hard, but combining them is equally non-trivial. +In the previous section, you learnt about how using multiple different hash functions can help reduce the chance of collisions in the bloom filter. However, good hash functions are difficult to design. A simple alternative to multiple hash functions is to use a set of random numbers. + +As an example, let's say a bloom filter wants to hash each element 15 times during insertion. Instead of using 15 different hash functions, you can rely on just one hash function. The hash value can then be combined with 15 different values to form the indices for flipping. This bloom filter would initialize a set of 15 random numbers ahead of time and use these values during each insertion. ``` hash("Hello world!") >> hash(987654321) // would flip bit 8 From f9133844436bd6336595e0f6b66038f676dd3b3a Mon Sep 17 00:00:00 2001 From: gmotzespina Date: Mon, 5 Nov 2018 19:00:34 -0600 Subject: [PATCH 155/271] Swift 4.2 Migration #748 - Depth First Search migrated to Swift 4.2 --- .../APSP/APSP.xcodeproj/project.pbxproj | 8 +++++--- .../Pages/Simple Example.xcplaygroundpage/Contents.swift | 5 +---- Depth-First Search/Tests/Tests.xcodeproj/project.pbxproj | 4 ++-- 3 files changed, 8 insertions(+), 9 deletions(-) diff --git a/All-Pairs Shortest Paths/APSP/APSP.xcodeproj/project.pbxproj b/All-Pairs Shortest Paths/APSP/APSP.xcodeproj/project.pbxproj index 78df3fb76..908d32785 100644 --- a/All-Pairs Shortest Paths/APSP/APSP.xcodeproj/project.pbxproj +++ b/All-Pairs Shortest Paths/APSP/APSP.xcodeproj/project.pbxproj @@ -196,7 +196,7 @@ }; 493D8DF01CDD5B960089795A = { CreatedOnToolsVersion = 7.3; - LastSwiftMigration = 0820; + LastSwiftMigration = 1010; }; }; }; @@ -420,7 +420,8 @@ PRODUCT_BUNDLE_IDENTIFIER = "com.swift-algorithm-club.APSP"; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; - SWIFT_VERSION = 3.0; + SWIFT_SWIFT3_OBJC_INFERENCE = On; + SWIFT_VERSION = 4.2; VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; }; @@ -442,7 +443,8 @@ PRODUCT_BUNDLE_IDENTIFIER = "com.swift-algorithm-club.APSP"; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; - SWIFT_VERSION = 3.0; + SWIFT_SWIFT3_OBJC_INFERENCE = On; + SWIFT_VERSION = 4.2; VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; }; diff --git a/Depth-First Search/DepthFirstSearch.playground/Pages/Simple Example.xcplaygroundpage/Contents.swift b/Depth-First Search/DepthFirstSearch.playground/Pages/Simple Example.xcplaygroundpage/Contents.swift index 99f20a729..c83f52af8 100644 --- a/Depth-First Search/DepthFirstSearch.playground/Pages/Simple Example.xcplaygroundpage/Contents.swift +++ b/Depth-First Search/DepthFirstSearch.playground/Pages/Simple Example.xcplaygroundpage/Contents.swift @@ -1,7 +1,4 @@ -// last checked with Xcode 9.0b4 -#if swift(>=4.0) -print("Hello, Swift 4!") -#endif +// last checked with Xcode 10.1 func depthFirstSearch(_ graph: Graph, source: Node) -> [String] { var nodesExplored = [source.label] diff --git a/Depth-First Search/Tests/Tests.xcodeproj/project.pbxproj b/Depth-First Search/Tests/Tests.xcodeproj/project.pbxproj index 8f6058600..2b433bd96 100644 --- a/Depth-First Search/Tests/Tests.xcodeproj/project.pbxproj +++ b/Depth-First Search/Tests/Tests.xcodeproj/project.pbxproj @@ -234,7 +234,7 @@ PRODUCT_BUNDLE_IDENTIFIER = swift.algorithm.club.Tests; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 4.0; + SWIFT_VERSION = 4.2; }; name = Debug; }; @@ -247,7 +247,7 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = swift.algorithm.club.Tests; PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 4.0; + SWIFT_VERSION = 4.2; }; name = Release; }; From 0f739b5230f7fe0df655fac82941e9111d346b90 Mon Sep 17 00:00:00 2001 From: gmotzespina Date: Mon, 5 Nov 2018 19:08:43 -0600 Subject: [PATCH 156/271] Swift 4.2 support Depth-First Search --- .../DepthFirstSearch.playground/Edge.o | Bin 0 -> 7016 bytes .../DepthFirstSearch.playground/Graph.o | Bin 0 -> 21488 bytes .../DepthFirstSearch.playground/Node.o | Bin 0 -> 19288 bytes .../xcshareddata/IDEWorkspaceChecks.plist | 8 ++++++++ .../xcshareddata/WorkspaceSettings.xcsettings | 8 ++++++++ 5 files changed, 16 insertions(+) create mode 100644 Depth-First Search/DepthFirstSearch.playground/Edge.o create mode 100644 Depth-First Search/DepthFirstSearch.playground/Graph.o create mode 100644 Depth-First Search/DepthFirstSearch.playground/Node.o create mode 100644 swift-algorithm-club.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist create mode 100644 swift-algorithm-club.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings diff --git a/Depth-First Search/DepthFirstSearch.playground/Edge.o b/Depth-First Search/DepthFirstSearch.playground/Edge.o new file mode 100644 index 0000000000000000000000000000000000000000..ab1e89b3aa83ed547413ba061a5edfd5dc918137 GIT binary patch literal 7016 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 literal 0 HcmV?d00001 diff --git a/Depth-First Search/DepthFirstSearch.playground/Graph.o b/Depth-First Search/DepthFirstSearch.playground/Graph.o new file mode 100644 index 0000000000000000000000000000000000000000..dde35fb0f1a416f1a99b083ab8937861bd8038af GIT binary patch literal 21488 zcmdUX4|H5db@#KeV+G5y2oOxbWFe+8A+{yQ{}Pg-wY>IIBE_;-vR&eIwU$=WCac{= zyK74ZwQIx{J-=)#dQj_A(pLRL>$aGxr*)4K&_OY7EK*2R4kT{-rHJp)Rw1TUIR#8g zP=CLf`*zYYbz>8w~t|5AKcW8}N@0 zA6#$8XMVN1E&I=g&ANDwGPtU4*GN75+@wh(6iP=1(n0`2p|-%Wwj%A^J`>IV&)?=R(&M7X$4=qO`V518JhsCy-ogUU6$*8x(*4nR zkCc1uo4!R?tP_3X@7DG?YF0Wo1^LveXm@%?C_R{r^hdhA`o8)O&G?A$UwDtcxeoh8 zSFKbj2!%vnXE>S8^hdn<_PkSb*NM=E+q9mlorWQy@#yPJ#8c@)6JG!IioUDDVL~7M zw+H%s1*zf<{O8eE8sCPEn)i~3_%?~YU6u5mNTrJEm&CVL##xobgRC4c&gCjrMWImQ z#3P+WBfb5tdY6`*6b18+eY*?(b5x5yi3egE!^rW*V_Niy?~U>ImWY$^#6$FTM3sXP=&KU5E{nc%&?kN@uaDyyf$`dRP4qc2 z_=@P8guZ3QbEq%T)f-OrLSJ+9krpuqups&zBW9QSugHu$C%&<8Diw>S(%$$Qw`z8$ zzjM&X@jL_jWUM$%DMry3?F;urqVev8S6`J!-~3YhJo-8leaUcVI+Tf@ipCM&=6%{C z{co-4%hD)Z3u50a?30*_8+Cms6zL6h_lNr;4qZCmM&F~$2P7cL_v!xXQo~q_q2t^W zx8t(`AJxc;Y8I)BG|MOU7{+73q#wByNgeV=D?YrC8q^0Y#zXkj2=rSA2& zew-pozrP(V>@lsOt58)C1Lu|6C*BPnw%45RLqq>URbZMfsW7gHG*` zm^FNPkN@F^zqI~Vj2P7)>xYUJW{i^dx3@M8{}t6#O{(@THCz9RRu;6v{99=#I=2AZ ztEj2Fd+QSWH`GsCSCqgL^sn{o6I{OOiJ=8LisDu~e0E7OHCcb9wGUt3pp7f~1Kxl! zt5vJR*A4Xfdgc~0e;+4=7NX;Iy)|?ls;}37*?I=n)zUUzCH6sI2dsMvaY3&Tjut0g zL-53k!cT|FBT48?hu1Z?8SIEbL|{DtBoF-Q3EP74dW+ae8Co!2hPJ%rx`HX;IjKr z7&xb!VXxtNJ21)N>$VkLzXIL~XdG>}UIN>Q(@AL|&&WLuo)I*X)s=be_S|&(rk4#< zC@VLxxVZT8%9jtDwz@?)o-^%sSlbTQ=8~ut@yt~-KQ!BH2cUDR7v;^gBF8(^8tYI6 zmoPY>h*FEQFn!cKbD8eoIFb2Sr(9#}kvaT|fl+oHjltfQ`HVTa2yPjT@HlD^TbPrtOF5yq;0+O+RMkIq4^$@&H?z+GT;@lZ#getI7UXkMA5qGDQk z`d)XNtw(9>A%wL?Ixp7B{TE?f&DG4P1+^D)68!6P=Q@SXZEf(ci zjnVR(*vsgZ?wKdlfU%y3rv^}o1qqptH~CmWPABXME(6HbPA0#olvy{J){!dMNk?Jm znD*gb4xg{VTSx%yt7^0fbLOoYsz5RLCv{esvxVZ4)PzMiN$y)PD16O~}BL((40yZyM z=3v_i_A&O*x`eUD$Tr)bDFmb0`j$ETBcs{+OsnF_nSk}VPs6tmCxNk{#d8gyWXKHZ zYXc22|8Ri!RhTa;1v7=4`oFa7&}fEjD9w2tkl&289Jl@>D;j9q`V#E9HN zfwsqla~?&eHH+Yr8EY~VrvEq-yk0*gF8Mh}cKuqlzbv<(yA2|GyQrpL`+|7ylId*h z+SSHRHg$#dw$-%PnAW|UASE4Iwdv

    oMAESZ;sNUa~*XDf_D99<-W46eQ|}%>q)l zXS0BkN}C1b_!)S42F7!*@7|BTmi@0)FZ-Wb)3ZPR@ARiSpKPGx?FM9qSGmaVG3{Su zc0z7iSbPD=WdU~>R?aRchuLdAJ*f^T zJnN{~^MKSK=do5;(qw09o9y-tus{Z9;q9?eF-G>#gto$+)1T3c z*t1|hZ(7e|!v|;|Z$@@6o+U29_Y*43+e1(}0N>Etqu`XYgH{PPELQE%5RhX7)VLN2 zEJM%&=^r9V4KP7k?!D^Jw6>4CcK68uIr>;3jp_vkD+@YwQR%RC%C(+qwj)|Y)9{ZC zsAz@I`rLc<5<&t=R~7}cpbyKVcx7nbxxtvrlLJEluFEy3TeTAt4vt8@GqZAas`fex zXe5kc0k$uWGA9A!td0c^>NYEZybqvuP`p9$2EfZbFB|;N%&&gvja*s3Wm+q)_&IK| z74>i6%@sfMFUhKYV*bAGkTt*Vj{r~d`HJ=YlXnCB*6fqyw8q{7)%)x`L0PqaEmje> z$7Bxolq7TQp?sCY%ngJ{dB(rW51VyZs=b0dLo zs{6BnZ(=-e<{WnBAJ>Z}d#D!YT|Hk)CoBwcrcvR*UsxZQADx-2^n3Cz>-F=NW(%pr z$v@0J|JTH{Y_=lvBY}Tr`pMjM7B{fF$@&URRL@YDh>B?j{c|20*i2P{>4p((pd;8E zYj*v7rPTZi`DV_s8fsoU-_)A_MfqR+apu}2vj^5>oOE=It^{TMYw|80PNH2kt@N2och{b(1-Elgh3fvLZMZY@PSU~Y z*|gWINtCNX4Gv5=?oWeZhU3e$mbj>pV4SR}&u@7o|2!W(O!DIh1b3lYY1tzk)`KzGs7_NE_mTRH zXJ2H2D^ZR+Y9>)Gp+1KeCJHUEReOpwEIqG)ZsDB{^>~5R#?eXl@Epoi4|xN*Q2=_l zRxb;rknPzw(|(iEqKOb*v!FAo^*KXMOnJydP(NfxyW@fYTVy5ws)_1zQC9TWKQiOPT1RnYxVJkb@o$7lE=T|JQ$ZXPaaa$9>U z(x2Ma)0aq}j--;&czD~sNb1paBDqa{iMAyi>q+!S)4hFLI%Am=s7$7Nx9pGhr_#P) zB;4QGtBX{LF4&rkg$H~36Pb9|wqPRD-x*15JJ26a_HI=gOPV*@EE6&Iht_gV$r%>=3H$K#}edoF&^3MA~ zY_AHREIzbPJxv8V*XwOh4}3?OZC9)I={v^ryu2qt-;(QBI&c2^g~?Ao_W6IUf5%(b zZhxsLX&4>O%P1&3sw>=GQ6(L^+;|lD24lsN`dO*3(YU03PU`t=ww%0AB+Lr+(^CJt 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 literal 0 HcmV?d00001 diff --git a/Depth-First Search/DepthFirstSearch.playground/Node.o b/Depth-First Search/DepthFirstSearch.playground/Node.o new file mode 100644 index 0000000000000000000000000000000000000000..1090b3a9cbf150965dc206734fec12c24cda0982 GIT binary patch literal 19288 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 WO2$%2gh>zf&_PY60#Acy_5T4cZe^PQ literal 0 HcmV?d00001 diff --git a/swift-algorithm-club.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/swift-algorithm-club.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/swift-algorithm-club.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/swift-algorithm-club.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/swift-algorithm-club.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 000000000..08de0be8d --- /dev/null +++ b/swift-algorithm-club.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,8 @@ + + + + + IDEWorkspaceSharedSettings_AutocreateContextsIfNeeded + + + From 07732e85027602ed909f9afbd9ebb2869ba18632 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Francisco=20Salda=C3=B1a?= Date: Mon, 5 Nov 2018 19:18:53 -0600 Subject: [PATCH 157/271] fix deprecated methods and return type --- .../BoyerMooreHorspool.playground/Contents.swift | 10 +++++----- .../xcshareddata/IDEWorkspaceChecks.plist | 8 ++++++++ .../BoyerMooreHorspool.playground/timeline.xctimeline | 6 +++--- Boyer-Moore-Horspool/BoyerMooreHorspool.swift | 10 +++++----- 4 files changed, 21 insertions(+), 13 deletions(-) create mode 100644 Boyer-Moore-Horspool/BoyerMooreHorspool.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist diff --git a/Boyer-Moore-Horspool/BoyerMooreHorspool.playground/Contents.swift b/Boyer-Moore-Horspool/BoyerMooreHorspool.playground/Contents.swift index e88a1b93d..c51070caf 100644 --- a/Boyer-Moore-Horspool/BoyerMooreHorspool.playground/Contents.swift +++ b/Boyer-Moore-Horspool/BoyerMooreHorspool.playground/Contents.swift @@ -13,16 +13,16 @@ http://www.drdobbs.com/database/faster-string-searches/184408171 */ extension String { - func index(of pattern: String, usingHorspoolImprovement: Bool = false) -> Index? { + func index(of pattern: String, usingHorspoolImprovement: Bool = false) -> Int? { // Cache the length of the search pattern because we're going to // use it a few times and it's expensive to calculate. - let patternLength = pattern.characters.count - guard patternLength > 0, patternLength <= characters.count else { return nil } + let patternLength = pattern.count + guard patternLength > 0, patternLength <= self.count else { return nil } // Make the skip table. This table determines how far we skip ahead // when a character from the pattern is found. var skipTable = [Character: Int]() - for (i, c) in pattern.characters.enumerated() { + for (i, c) in pattern.enumerated() { skipTable[c] = patternLength - i - 1 } @@ -57,7 +57,7 @@ extension String { if c == lastChar { // There is a possible match. Do a brute-force search backwards. - if let k = backwards() { return k } + if let k = backwards() { return k.encodedOffset } if !usingHorspoolImprovement { // If no match, we can only safely skip one character ahead. diff --git a/Boyer-Moore-Horspool/BoyerMooreHorspool.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Boyer-Moore-Horspool/BoyerMooreHorspool.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/Boyer-Moore-Horspool/BoyerMooreHorspool.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/Boyer-Moore-Horspool/BoyerMooreHorspool.playground/timeline.xctimeline b/Boyer-Moore-Horspool/BoyerMooreHorspool.playground/timeline.xctimeline index 89bc76f90..431d4a349 100644 --- a/Boyer-Moore-Horspool/BoyerMooreHorspool.playground/timeline.xctimeline +++ b/Boyer-Moore-Horspool/BoyerMooreHorspool.playground/timeline.xctimeline @@ -3,17 +3,17 @@ version = "3.0"> diff --git a/Boyer-Moore-Horspool/BoyerMooreHorspool.swift b/Boyer-Moore-Horspool/BoyerMooreHorspool.swift index af8aea9d9..92d2ee4c1 100644 --- a/Boyer-Moore-Horspool/BoyerMooreHorspool.swift +++ b/Boyer-Moore-Horspool/BoyerMooreHorspool.swift @@ -6,16 +6,16 @@ http://www.drdobbs.com/database/faster-string-searches/184408171 */ extension String { - func index(of pattern: String, usingHorspoolImprovement: Bool = false) -> Index? { + func index(of pattern: String, usingHorspoolImprovement: Bool = false) -> Int? { // Cache the length of the search pattern because we're going to // use it a few times and it's expensive to calculate. - let patternLength = pattern.characters.count - guard patternLength > 0, patternLength <= characters.count else { return nil } + let patternLength = pattern.count + guard patternLength > 0, patternLength <= self.count else { return nil } // Make the skip table. This table determines how far we skip ahead // when a character from the pattern is found. var skipTable = [Character: Int]() - for (i, c) in pattern.characters.enumerated() { + for (i, c) in pattern.enumerated() { skipTable[c] = patternLength - i - 1 } @@ -50,7 +50,7 @@ extension String { if c == lastChar { // There is a possible match. Do a brute-force search backwards. - if let k = backwards() { return k } + if let k = backwards() { return k.encodedOffset } if !usingHorspoolImprovement { // If no match, we can only safely skip one character ahead. From 17990d8b52ae03bae0570f5e97e18d5f75485136 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Francisco=20Salda=C3=B1a?= Date: Mon, 5 Nov 2018 19:37:55 -0600 Subject: [PATCH 158/271] change return type --- .../BoyerMooreHorspool.playground/Contents.swift | 4 ++-- .../BoyerMooreHorspool.playground/timeline.xctimeline | 6 +++--- Boyer-Moore-Horspool/BoyerMooreHorspool.swift | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Boyer-Moore-Horspool/BoyerMooreHorspool.playground/Contents.swift b/Boyer-Moore-Horspool/BoyerMooreHorspool.playground/Contents.swift index c51070caf..eba2a5806 100644 --- a/Boyer-Moore-Horspool/BoyerMooreHorspool.playground/Contents.swift +++ b/Boyer-Moore-Horspool/BoyerMooreHorspool.playground/Contents.swift @@ -13,7 +13,7 @@ http://www.drdobbs.com/database/faster-string-searches/184408171 */ extension String { - func index(of pattern: String, usingHorspoolImprovement: Bool = false) -> Int? { + func index(of pattern: String, usingHorspoolImprovement: Bool = false) -> Index? { // Cache the length of the search pattern because we're going to // use it a few times and it's expensive to calculate. let patternLength = pattern.count @@ -57,7 +57,7 @@ extension String { if c == lastChar { // There is a possible match. Do a brute-force search backwards. - if let k = backwards() { return k.encodedOffset } + if let k = backwards() { return k } if !usingHorspoolImprovement { // If no match, we can only safely skip one character ahead. diff --git a/Boyer-Moore-Horspool/BoyerMooreHorspool.playground/timeline.xctimeline b/Boyer-Moore-Horspool/BoyerMooreHorspool.playground/timeline.xctimeline index 431d4a349..5eb7f2337 100644 --- a/Boyer-Moore-Horspool/BoyerMooreHorspool.playground/timeline.xctimeline +++ b/Boyer-Moore-Horspool/BoyerMooreHorspool.playground/timeline.xctimeline @@ -3,17 +3,17 @@ version = "3.0"> diff --git a/Boyer-Moore-Horspool/BoyerMooreHorspool.swift b/Boyer-Moore-Horspool/BoyerMooreHorspool.swift index 92d2ee4c1..1dd37873a 100644 --- a/Boyer-Moore-Horspool/BoyerMooreHorspool.swift +++ b/Boyer-Moore-Horspool/BoyerMooreHorspool.swift @@ -6,7 +6,7 @@ http://www.drdobbs.com/database/faster-string-searches/184408171 */ extension String { - func index(of pattern: String, usingHorspoolImprovement: Bool = false) -> Int? { + func index(of pattern: String, usingHorspoolImprovement: Bool = false) -> Index? { // Cache the length of the search pattern because we're going to // use it a few times and it's expensive to calculate. let patternLength = pattern.count @@ -50,7 +50,7 @@ extension String { if c == lastChar { // There is a possible match. Do a brute-force search backwards. - if let k = backwards() { return k.encodedOffset } + if let k = backwards() { return k } if !usingHorspoolImprovement { // If no match, we can only safely skip one character ahead. From a7047d8bbb8cbdc023c8979dcfa22d15ba6ed21f Mon Sep 17 00:00:00 2001 From: Morgan Davison Date: Tue, 6 Nov 2018 20:09:29 -0500 Subject: [PATCH 159/271] Compile for Swift 4.2 --- B-Tree/BTree.playground/Contents.swift | 5 +--- .../xcshareddata/IDEWorkspaceChecks.plist | 8 +++++++ B-Tree/Tests/Tests.xcodeproj/project.pbxproj | 24 +++++++++++++++---- .../xcshareddata/IDEWorkspaceChecks.plist | 8 +++++++ .../xcshareddata/xcschemes/Tests.xcscheme | 2 +- 5 files changed, 38 insertions(+), 9 deletions(-) create mode 100644 B-Tree/BTree.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist create mode 100644 B-Tree/Tests/Tests.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist diff --git a/B-Tree/BTree.playground/Contents.swift b/B-Tree/BTree.playground/Contents.swift index a0643586f..f6325513a 100644 --- a/B-Tree/BTree.playground/Contents.swift +++ b/B-Tree/BTree.playground/Contents.swift @@ -2,10 +2,7 @@ import Foundation -// last checked with Xcode 9.0b4 -#if swift(>=4.0) -print("Hello, Swift 4!") -#endif +// last checked with Xcode 10.0 let bTree = BTree(order: 1)! diff --git a/B-Tree/BTree.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/B-Tree/BTree.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/B-Tree/BTree.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/B-Tree/Tests/Tests.xcodeproj/project.pbxproj b/B-Tree/Tests/Tests.xcodeproj/project.pbxproj index 3e12b9ac3..66eb85190 100644 --- a/B-Tree/Tests/Tests.xcodeproj/project.pbxproj +++ b/B-Tree/Tests/Tests.xcodeproj/project.pbxproj @@ -85,12 +85,12 @@ isa = PBXProject; attributes = { LastSwiftUpdateCheck = 0730; - LastUpgradeCheck = 0800; + LastUpgradeCheck = 1000; ORGANIZATIONNAME = "Viktor Szilárd Simkó"; TargetAttributes = { C66702771D0EEE25008CD769 = { CreatedOnToolsVersion = 7.3.1; - LastSwiftMigration = 0800; + LastSwiftMigration = 1000; }; }; }; @@ -144,14 +144,22 @@ CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; @@ -192,14 +200,22 @@ CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; @@ -234,7 +250,7 @@ PRODUCT_BUNDLE_IDENTIFIER = viktorsimko.Tests; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 4.0; + SWIFT_VERSION = 4.2; }; name = Debug; }; @@ -247,7 +263,7 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = viktorsimko.Tests; PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 4.0; + SWIFT_VERSION = 4.2; }; name = Release; }; diff --git a/B-Tree/Tests/Tests.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/B-Tree/Tests/Tests.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/B-Tree/Tests/Tests.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/B-Tree/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme b/B-Tree/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme index 9d6c542ae..d1555acfb 100644 --- a/B-Tree/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme +++ b/B-Tree/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme @@ -1,6 +1,6 @@ Date: Wed, 7 Nov 2018 22:38:11 -0800 Subject: [PATCH 160/271] Added Markdown Documentation to Stack playground This might be overkill for such a small file, but I wish I started using Swift Markdown early in my iOS career. Option click is too convenient to ignore! --- Stack/Stack.playground/Contents.swift | 28 +++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/Stack/Stack.playground/Contents.swift b/Stack/Stack.playground/Contents.swift index 1eb705f20..13774d7d1 100644 --- a/Stack/Stack.playground/Contents.swift +++ b/Stack/Stack.playground/Contents.swift @@ -1,4 +1,4 @@ -/* +/** Stack A stack is like an array but with limited functionality. You can only push @@ -9,27 +9,51 @@ last is the first one to come off with the next pop. Push and pop are O(1) operations. + + ## Usage + ``` + var myStack = Stack(array: []) + myStack.push(10) + myStack.push(3) + myStack.push(57) + myStack.pop() // 57 + myStack.pop() // 3 + ``` */ - public struct Stack { + + /// Datastructure consisting of a generic item. fileprivate var array = [T]() + /// The number of items in the stack. public var count: Int { return array.count } + /// Verifies if the stack is empty. public var isEmpty: Bool { return array.isEmpty } + /** + Pushes an item to the top of the stack. + + - Parameter element: The item being pushed. + */ public mutating func push(_ element: T) { array.append(element) } + /** + Removes and returns the item at the top of the sack. + + - Returns: The item at the top of the stack. + */ public mutating func pop() -> T? { return array.popLast() } + /// Returns the item at the top of the stack. public var top: T? { return array.last } From eb228cc1d18d860ad825c7d79063524121555bce Mon Sep 17 00:00:00 2001 From: Kelvin Reid Date: Sun, 11 Nov 2018 21:24:07 -0500 Subject: [PATCH 161/271] [Swift 4.2] Updated Hash Set --- Hash Set/HashSet.playground/Contents.swift | 4 ---- .../xcshareddata/IDEWorkspaceChecks.plist | 8 ++++++++ .../xcshareddata/IDEWorkspaceChecks.plist | 8 ++++++++ 3 files changed, 16 insertions(+), 4 deletions(-) create mode 100644 Hash Set/HashSet.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist create mode 100644 swift-algorithm-club.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist diff --git a/Hash Set/HashSet.playground/Contents.swift b/Hash Set/HashSet.playground/Contents.swift index 5edb76bb4..551c6dc86 100644 --- a/Hash Set/HashSet.playground/Contents.swift +++ b/Hash Set/HashSet.playground/Contents.swift @@ -1,8 +1,4 @@ //: Playground - noun: a place where people can play -// last checked with Xcode 9.0b4 -#if swift(>=4.0) -print("Hello, Swift 4!") -#endif var set = HashSet() diff --git a/Hash Set/HashSet.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Hash Set/HashSet.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/Hash Set/HashSet.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/swift-algorithm-club.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/swift-algorithm-club.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/swift-algorithm-club.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + From 67ecddaafb2e7637da0b24787ece79cadd82603c Mon Sep 17 00:00:00 2001 From: Kelvin Reid Date: Sun, 11 Nov 2018 21:37:44 -0500 Subject: [PATCH 162/271] [Swift 4.2] Updated Hash Table --- Hash Table/HashTable.playground/Contents.swift | 3 --- .../xcshareddata/IDEWorkspaceChecks.plist | 8 ++++++++ 2 files changed, 8 insertions(+), 3 deletions(-) create mode 100644 Hash Table/HashTable.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist diff --git a/Hash Table/HashTable.playground/Contents.swift b/Hash Table/HashTable.playground/Contents.swift index 273113440..121fb6032 100644 --- a/Hash Table/HashTable.playground/Contents.swift +++ b/Hash Table/HashTable.playground/Contents.swift @@ -1,8 +1,5 @@ //: Playground - noun: a place where people can play -#if swift(>=4.0) -print("Hello, Swift 4!") -#endif // Playing with hash values "firstName".hashValue diff --git a/Hash Table/HashTable.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Hash Table/HashTable.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/Hash Table/HashTable.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + From 70d26fccdea4e655986b0fe36cec2d2dae2ab8e8 Mon Sep 17 00:00:00 2001 From: Kelvin Reid Date: Sun, 11 Nov 2018 21:44:55 -0500 Subject: [PATCH 163/271] [Swift 4.2] Updated Heap Sort --- Heap Sort/Tests/HeapSortTests.swift | 6 ---- .../Tests/Tests.xcodeproj/project.pbxproj | 31 +++++++++++++------ .../xcshareddata/IDEWorkspaceChecks.plist | 8 +++++ .../xcshareddata/xcschemes/Tests.xcscheme | 4 +-- 4 files changed, 31 insertions(+), 18 deletions(-) create mode 100644 Heap Sort/Tests/Tests.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist diff --git a/Heap Sort/Tests/HeapSortTests.swift b/Heap Sort/Tests/HeapSortTests.swift index b36f605e3..dae1f8a68 100644 --- a/Heap Sort/Tests/HeapSortTests.swift +++ b/Heap Sort/Tests/HeapSortTests.swift @@ -1,12 +1,6 @@ import XCTest class HeapSortTests: XCTestCase { - func testSwift4() { - // last checked with Xcode 9.0b4 - #if swift(>=4.0) - print("Hello, Swift 4!") - #endif - } func testSort() { var h1 = Heap(array: [5, 13, 2, 25, 7, 17, 20, 8, 4], sort: >) diff --git a/Heap Sort/Tests/Tests.xcodeproj/project.pbxproj b/Heap Sort/Tests/Tests.xcodeproj/project.pbxproj index ff1f4937f..62e6d4e3f 100644 --- a/Heap Sort/Tests/Tests.xcodeproj/project.pbxproj +++ b/Heap Sort/Tests/Tests.xcodeproj/project.pbxproj @@ -3,7 +3,7 @@ archiveVersion = 1; classes = { }; - objectVersion = 46; + objectVersion = 51; objects = { /* Begin PBXBuildFile section */ @@ -86,17 +86,17 @@ isa = PBXProject; attributes = { LastSwiftUpdateCheck = 0720; - LastUpgradeCheck = 0900; + LastUpgradeCheck = 1010; ORGANIZATIONNAME = "Swift Algorithm Club"; TargetAttributes = { 7B2BBC7F1C779D720067B71D = { CreatedOnToolsVersion = 7.2; - LastSwiftMigration = 0820; + LastSwiftMigration = 1010; }; }; }; buildConfigurationList = 7B2BBC6C1C779D710067B71D /* Build configuration list for PBXProject "Tests" */; - compatibilityVersion = "Xcode 3.2"; + compatibilityVersion = "Xcode 10.0"; developmentRegion = English; hasScannedForEncodings = 0; knownRegions = ( @@ -149,12 +149,14 @@ CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; @@ -201,12 +203,14 @@ CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; @@ -230,7 +234,8 @@ MACOSX_DEPLOYMENT_TARGET = 10.11; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = macosx; - SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; }; name = Release; }; @@ -239,10 +244,14 @@ buildSettings = { COMBINE_HIDPI_IMAGES = YES; INFOPLIST_FILE = Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + "@loader_path/../Frameworks", + ); PRODUCT_BUNDLE_IDENTIFIER = swift.algorithm.club.Tests; PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 4.0; + SWIFT_VERSION = 4.2; }; name = Debug; }; @@ -251,10 +260,14 @@ buildSettings = { COMBINE_HIDPI_IMAGES = YES; INFOPLIST_FILE = Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + "@loader_path/../Frameworks", + ); PRODUCT_BUNDLE_IDENTIFIER = swift.algorithm.club.Tests; PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 4.0; + SWIFT_VERSION = 4.2; }; name = Release; }; diff --git a/Heap Sort/Tests/Tests.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Heap Sort/Tests/Tests.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/Heap Sort/Tests/Tests.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/Heap Sort/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme b/Heap Sort/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme index 538a6f4fa..1608804f9 100644 --- a/Heap Sort/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme +++ b/Heap Sort/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme @@ -1,6 +1,6 @@ Date: Sun, 11 Nov 2018 21:49:37 -0500 Subject: [PATCH 164/271] [Swift 4.2] Updated Heap --- Heap/Tests/HeapTests.swift | 7 ----- Heap/Tests/Tests.xcodeproj/project.pbxproj | 31 +++++++++++++------ .../xcshareddata/IDEWorkspaceChecks.plist | 8 +++++ .../xcshareddata/xcschemes/Tests.xcscheme | 4 +-- 4 files changed, 31 insertions(+), 19 deletions(-) create mode 100644 Heap/Tests/Tests.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist diff --git a/Heap/Tests/HeapTests.swift b/Heap/Tests/HeapTests.swift index 1ed15c726..ecf143778 100755 --- a/Heap/Tests/HeapTests.swift +++ b/Heap/Tests/HeapTests.swift @@ -7,13 +7,6 @@ import XCTest class HeapTests: XCTestCase { - func testSwift4() { - // last checked with Xcode 9.0b4 - #if swift(>=4.0) - print("Hello, Swift 4!") - #endif - } - fileprivate func verifyMaxHeap(_ h: Heap) -> Bool { for i in 0.. + + + + IDEDidComputeMac32BitWarning + + + diff --git a/Heap/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme b/Heap/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme index 77d01bebc..1608804f9 100755 --- a/Heap/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme +++ b/Heap/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme @@ -1,6 +1,6 @@ Date: Sun, 11 Nov 2018 23:00:22 -0500 Subject: [PATCH 165/271] Update Contents.swift --- HaversineDistance/HaversineDistance.playground/Contents.swift | 4 ---- 1 file changed, 4 deletions(-) diff --git a/HaversineDistance/HaversineDistance.playground/Contents.swift b/HaversineDistance/HaversineDistance.playground/Contents.swift index 7aa686645..3d8d60f54 100644 --- a/HaversineDistance/HaversineDistance.playground/Contents.swift +++ b/HaversineDistance/HaversineDistance.playground/Contents.swift @@ -1,8 +1,4 @@ import UIKit -// last checked with Xcode 9.04 -#if swift(>=4) -print("Hello, Swift 4!") -#endif func haversineDinstance(la1: Double, lo1: Double, la2: Double, lo2: Double, radius: Double = 6367444.7) -> Double { From ef4e890fd9f5b0ddf15cfa289fc2993ee46a9e04 Mon Sep 17 00:00:00 2001 From: Kelvin Lau Date: Sun, 11 Nov 2018 23:01:46 -0500 Subject: [PATCH 166/271] Updates Contents.swift --- .../BoyerMooreHorspool.playground/Contents.swift | 5 ----- 1 file changed, 5 deletions(-) diff --git a/Boyer-Moore-Horspool/BoyerMooreHorspool.playground/Contents.swift b/Boyer-Moore-Horspool/BoyerMooreHorspool.playground/Contents.swift index 5817cc41f..1666549c1 100644 --- a/Boyer-Moore-Horspool/BoyerMooreHorspool.playground/Contents.swift +++ b/Boyer-Moore-Horspool/BoyerMooreHorspool.playground/Contents.swift @@ -1,10 +1,5 @@ //: Playground - noun: a place where people can play -// last checked with Xcode 9.0b4 -#if swift(>=4.0) - print("Hello, Swift 4!") -#endif - /* Boyer-Moore string search From 9ba8b54dc580cc6cb3803a1a2cd2a9efcd5bf6ab Mon Sep 17 00:00:00 2001 From: gmotzespina Date: Mon, 12 Nov 2018 19:53:38 -0600 Subject: [PATCH 167/271] Bubble Sort Readme Code Issue #838 solved --- Bubble Sort/README.markdown | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Bubble Sort/README.markdown b/Bubble Sort/README.markdown index e55129d93..648b9f324 100644 --- a/Bubble Sort/README.markdown +++ b/Bubble Sort/README.markdown @@ -57,9 +57,9 @@ This is the same for the forth and fifth passes. ```swift for i in 0.. Date: Tue, 27 Nov 2018 14:22:02 -0600 Subject: [PATCH 168/271] Removing version check --- Tree/Tree.playground/Contents.swift | 5 ----- 1 file changed, 5 deletions(-) diff --git a/Tree/Tree.playground/Contents.swift b/Tree/Tree.playground/Contents.swift index 06f992fa8..1fad157a0 100644 --- a/Tree/Tree.playground/Contents.swift +++ b/Tree/Tree.playground/Contents.swift @@ -1,10 +1,5 @@ //: Playground - noun: a place where people can play -// last checked with Xcode 9.0b4 -#if swift(>=4.2) -print("Hello, Swift 4.2!") -#endif - let tree = TreeNode(value: "beverages") let hotNode = TreeNode(value: "hot") From f1363dd983ccacf1e48d9d393022f3ce68ba3c39 Mon Sep 17 00:00:00 2001 From: Francesco Scalise Date: Tue, 4 Dec 2018 19:31:26 +0100 Subject: [PATCH 169/271] [Swift 4.2] Count occurences --- Count Occurrences/CountOccurrences.playground/Contents.swift | 4 ---- 1 file changed, 4 deletions(-) diff --git a/Count Occurrences/CountOccurrences.playground/Contents.swift b/Count Occurrences/CountOccurrences.playground/Contents.swift index 6138b74ac..a34e3485f 100644 --- a/Count Occurrences/CountOccurrences.playground/Contents.swift +++ b/Count Occurrences/CountOccurrences.playground/Contents.swift @@ -1,7 +1,3 @@ -// last checked with Xcode 9.0b4 -#if swift(>=4.0) - print("Hello, Swift 4!") -#endif func countOccurrencesOfKey(_ key: Int, inArray a: [Int]) -> Int { func leftBoundary() -> Int { From a2953343f16129995f90cfc6cf49236b3bcb9ae5 Mon Sep 17 00:00:00 2001 From: Morgan Kan Date: Sun, 16 Dec 2018 21:46:06 +0000 Subject: [PATCH 170/271] Implement bit shift operations in BitSet --- Bit Set/BitSet.playground/Contents.swift | 20 ++++++++ .../BitSet.playground/Sources/BitSet.swift | 46 +++++++++++++++++- Bit Set/BitSet.swift | 47 ++++++++++++++++++- 3 files changed, 111 insertions(+), 2 deletions(-) diff --git a/Bit Set/BitSet.playground/Contents.swift b/Bit Set/BitSet.playground/Contents.swift index d11b36e8c..2c5edcd84 100644 --- a/Bit Set/BitSet.playground/Contents.swift +++ b/Bit Set/BitSet.playground/Contents.swift @@ -89,3 +89,23 @@ z.all1() // false //var bigBits = BitSet(size: 10000) //print(bigBits) + +var smallBitSet = BitSet(size: 16) +smallBitSet[5] = true +smallBitSet[10] = true +print( smallBitSet >> 3 ) +print( smallBitSet << 6 ) // one bit shifts off the end + +var bigBitSet = BitSet( size: 120 ) +bigBitSet[1] = true +bigBitSet[3] = true +bigBitSet[7] = true +bigBitSet[32] = true +bigBitSet[55] = true +bigBitSet[64] = true +bigBitSet[80] = true +print( bigBitSet ) +print( bigBitSet << 32 ) +print( bigBitSet << 64 ) +print( bigBitSet >> 32 ) +print( bigBitSet >> 64 ) diff --git a/Bit Set/BitSet.playground/Sources/BitSet.swift b/Bit Set/BitSet.playground/Sources/BitSet.swift index 59306f5a5..85f5da505 100644 --- a/Bit Set/BitSet.playground/Sources/BitSet.swift +++ b/Bit Set/BitSet.playground/Sources/BitSet.swift @@ -9,7 +9,7 @@ public struct BitSet { We store the bits in a list of unsigned 64-bit integers. The first entry, `words[0]`, is the least significant word. */ - private let N = 64 + fileprivate let N = 64 public typealias Word = UInt64 fileprivate(set) public var words: [Word] @@ -221,6 +221,50 @@ prefix public func ~ (rhs: BitSet) -> BitSet { return out } +// MARK: - Bit shift operations + +/* + Note: For bitshift operations, the assumption is that any bits that are + shifted off the end of the end of the declared size are not still set. + In other words, we are maintaining the original number of bits. + */ + +public func << (lhs: BitSet, numBitsLeft: Int) -> BitSet { + var out = lhs + let offset = numBitsLeft / lhs.N + let shift = numBitsLeft % lhs.N + for i in 0..= 0 ) { + out.words[i] = lhs.words[i - offset] << shift + } + if( i - offset - 1 >= 0 ) { + out.words[i] |= lhs.words[i - offset - 1] >> (lhs.N - shift) + } + } + + out.clearUnusedBits() + return out +} + +public func >> (lhs: BitSet, numBitsRight: Int) -> BitSet { + var out = lhs + let offset = numBitsRight / lhs.N + let shift = numBitsRight % lhs.N + for i in 0..> shift + } + if( i + offset + 1 < lhs.words.count ) { + out.words[i] |= lhs.words[i + offset + 1] << (lhs.N - shift) + } + } + + out.clearUnusedBits() + return out +} + // MARK: - Debugging extension UInt64 { diff --git a/Bit Set/BitSet.swift b/Bit Set/BitSet.swift index cfe8517b5..83829c6c5 100644 --- a/Bit Set/BitSet.swift +++ b/Bit Set/BitSet.swift @@ -9,7 +9,7 @@ public struct BitSet { We store the bits in a list of unsigned 64-bit integers. The first entry, `words[0]`, is the least significant word. */ - private let N = 64 + fileprivate let N = 64 public typealias Word = UInt64 fileprivate(set) public var words: [Word] @@ -221,6 +221,51 @@ prefix public func ~ (rhs: BitSet) -> BitSet { return out } +// MARK: - Bit shift operations + +/* + Note: For bitshift operations, the assumption is that any bits that are + shifted off the end of the end of the declared size are not still set. + In other words, we are maintaining the original number of bits. + */ + +public func << (lhs: BitSet, numBitsLeft: Int) -> BitSet { + var out = lhs + let offset = numBitsLeft / lhs.N + let shift = numBitsLeft % lhs.N + for i in 0..= 0 ) { + out.words[i] = lhs.words[i - offset] << shift + } + if( i - offset - 1 >= 0 ) { + out.words[i] |= lhs.words[i - offset - 1] >> (lhs.N - shift) + } + } + + out.clearUnusedBits() + return out +} + +public func >> (lhs: BitSet, numBitsRight: Int) -> BitSet { + var out = lhs + let offset = numBitsRight / lhs.N + let shift = numBitsRight % lhs.N + for i in 0..> shift + } + if( i + offset + 1 < lhs.words.count ) { + out.words[i] |= lhs.words[i + offset + 1] << (lhs.N - shift) + } + } + + out.clearUnusedBits() + return out +} + + // MARK: - Debugging extension UInt64 { From dd182db605004ecdea85cf9b95de13b4006d52e3 Mon Sep 17 00:00:00 2001 From: Kelvin Lau Date: Thu, 20 Dec 2018 19:36:18 -0500 Subject: [PATCH 171/271] Fixes a typo --- A-Star/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/A-Star/README.md b/A-Star/README.md index f362bb61e..b373d25fc 100644 --- a/A-Star/README.md +++ b/A-Star/README.md @@ -16,7 +16,7 @@ On the first step we expand the root node on the left (blue). We set the cost `g ![Step 1](Images/step1.png) -We put the first not in the closed list (light blue) so that we don't try expanding it again if there were to be loops in the graph. Next we take the node on the open list with the smallest value of `g + h` where `g` is the current cost (0) plus the edge cost (1). Since all nodes in the open list have the same value we choose the top one. +We put the first node in the closed list (light blue) so that we don't try expanding it again if there were to be loops in the graph. Next we take the node on the open list with the smallest value of `g + h` where `g` is the current cost (0) plus the edge cost (1). Since all nodes in the open list have the same value we choose the top one. ![Step 2](Images/step2.png) From 1f15eda576530fdf76bb8245eecb99a5b4233a48 Mon Sep 17 00:00:00 2001 From: Andrzej Michnia Date: Sun, 16 Dec 2018 22:44:30 +0100 Subject: [PATCH 172/271] Fixed error in description --- Comb Sort/README.markdown | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Comb Sort/README.markdown b/Comb Sort/README.markdown index d30d429b3..20c939307 100644 --- a/Comb Sort/README.markdown +++ b/Comb Sort/README.markdown @@ -64,8 +64,8 @@ This will sort the values of the array into ascending order -- increasing in val ## Performance Comb Sort was created to improve upon the worst case time complexity of Bubble Sort. With Comb -Sort, the worst case scenario for performance is exponential -- O(n^2). At best though, Comb Sort -performs at O(n logn) time complexity. This creates a drastic improvement over Bubble Sort's performance. +Sort, the worst case scenario for performance is polynomial -- O(n^2). At best though, Comb Sort +performs at O(n logn) time complexity -- loglinear. This creates a drastic improvement over Bubble Sort's performance. Similar to Bubble Sort, the space complexity for Comb Sort is constant -- O(1). This is extremely space efficient as it sorts the array in place. From a9c311588b2ecee2420af4cfee91217db427f450 Mon Sep 17 00:00:00 2001 From: Mac Bellingrath Date: Wed, 26 Dec 2018 15:27:08 -0500 Subject: [PATCH 173/271] Update README.md --- Convex Hull/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Convex Hull/README.md b/Convex Hull/README.md index d27027a45..ab263f00d 100644 --- a/Convex Hull/README.md +++ b/Convex Hull/README.md @@ -2,7 +2,7 @@ Given a group of points on a plane. The Convex Hull algorithm calculates the shape (made up from the points itself) containing all these points. It can also be used on a collection of points of different dimensions. This implementation however covers points on a plane. It essentially calculates the lines between points which together contain all points. In comparing different solutions to this problem we can describe each algorithm in terms of it's big-O time complexity. -There are multiple Convex Hull algorithms but this solution is called Quickhull, is comes from the work of both W. Eddy in 1977 and also separately A. Bykat in 1978, this algorithm has an expected time complexity of O(n log n), but it's worst-case time-complexity can be O(n^2) . With average conditions the algorithm has ok efficiency, but it's time-complexity can start to head become more exponential in cases of high symmetry or where there are points lying on the circumference of a circle for example. +There are multiple Convex Hull algorithms but this solution is called Quickhull, is comes from the work of both W. Eddy in 1977 and also separately A. Bykat in 1978, this algorithm has an expected time complexity of O(n log n), but it's worst-case time-complexity can be O(n^2) . With average conditions the algorithm has ok efficiency, but it's time-complexity can start to become more exponential in cases of high symmetry or where there are points lying on the circumference of a circle for example. ## Quickhull From c1b704dfbe27b96a67a34949055bcc55a47ca7c3 Mon Sep 17 00:00:00 2001 From: Mac Bellingrath Date: Thu, 27 Dec 2018 09:14:45 -0500 Subject: [PATCH 174/271] Update README.md --- Convex Hull/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Convex Hull/README.md b/Convex Hull/README.md index d27027a45..71a470f56 100644 --- a/Convex Hull/README.md +++ b/Convex Hull/README.md @@ -17,7 +17,7 @@ The quickhull algorithm works as follows: - Keep on doing so on until no more points are left, the recursion has come to an end and the points selected constitute the convex hull. -Our functioni will have the following defininition: +Our function will have the following defininition: `findHull(points: [CGPoint], p1: CGPoint, p2: CGPoint)` From 611253f617661d54280dd2861dfe57b3e4568b4e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20C=2E=20Kr=C3=BCger?= Date: Fri, 11 Jan 2019 10:43:51 +0100 Subject: [PATCH 175/271] GCD improvements after review - Default parameter values - umbrella for different gcd implementations with generic gcd(_: _:) function - better structure of readme file including all 3 algorithms --- GCD/GCD.playground/Contents.swift | 154 ++------------------- GCD/{ => GCD.playground/Sources}/GCD.swift | 35 +++-- GCD/README.markdown | 146 ++++++++++++++----- 3 files changed, 151 insertions(+), 184 deletions(-) rename GCD/{ => GCD.playground/Sources}/GCD.swift (73%) diff --git a/GCD/GCD.playground/Contents.swift b/GCD/GCD.playground/Contents.swift index 175d26639..bb8d49055 100644 --- a/GCD/GCD.playground/Contents.swift +++ b/GCD/GCD.playground/Contents.swift @@ -1,147 +1,21 @@ -//: Playground - noun: a place where people can play +gcd(52, 39) // 13 +gcd(228, 36) // 12 +gcd(51357, 3819) // 57 +gcd(841, 299) // 1 -/* - Iterative approach based on the Euclidean algorithm. - The Euclidean algorithm is based on the principle that the greatest - common divisor of two numbers does not change if the larger number - is replaced by its difference with the smaller number. - - Parameter m: First natural number - - Parameter n: Second natural number - - Returns: The natural gcd if m and n - */ -func gcdIterativeEuklid(_ m: Int, _ n: Int) -> Int { - var a: Int = 0 - var b: Int = max(m, n) - var r: Int = min(m, n) - - while r != 0 { - a = b - b = r - r = a % b - } - return b -} - -/* - Recursive approach based on the Euclidean algorithm. - - - Parameter m: First natural number - - Parameter n: Second natural number - - Returns: The natural gcd of m and n - - Note: The recursive version makes only tail recursive calls. - Most compilers for imperative languages do not optimize these. - The swift compiler as well as the obj-c compiler is able to do - optimizations for tail recursive calls, even though it still ends - up to be the same in terms of complexity. That said, tail call - elimination is not mutually exclusive to recursion. - */ -func gcdRecursiveEuklid(_ m: Int, _ n: Int) -> Int { - let r: Int = m % n - if r != 0 { - return gcdRecursiveEuklid(n, r) - } else { - return n - } -} - -/* - The binary GCD algorithm, also known as Stein's algorithm, - is an algorithm that computes the greatest common divisor of two - nonnegative integers. Stein's algorithm uses simpler arithmetic - operations than the conventional Euclidean algorithm; it replaces - division with arithmetic shifts, comparisons, and subtraction. - - - Parameter m: First natural number - - Parameter n: Second natural number - - Returns: The natural gcd of m and n - - Complexity: worst case O(n^2), where n is the number of bits - in the larger of the two numbers. Although each step reduces - at least one of the operands by at least a factor of 2, - the subtract and shift operations take linear time for very - large integers - */ -func gcdBinaryRecursiveStein(_ m: Int, _ n: Int) -> Int { - if let easySolution = findEasySolution(m, n) { return easySolution } - - if (m & 1) == 0 { - // m is even - if (n & 1) == 1 { - // and n is odd - return gcdBinaryRecursiveStein(m >> 1, n) - } else { - // both m and n are even - return gcdBinaryRecursiveStein(m >> 1, n >> 1) << 1 - } - } else if (n & 1) == 0 { - // m is odd, n is even - return gcdBinaryRecursiveStein(m, n >> 1) - } else if (m > n) { - // reduce larger argument - return gcdBinaryRecursiveStein((m - n) >> 1, n) - } else { - // reduce larger argument - return gcdBinaryRecursiveStein((n - m) >> 1, m) - } -} - -/* - Finds an easy solution for the gcd. - - Note: It might be relevant for different usecases to - try finding an easy solution for the GCD calculation - before even starting more difficult operations. - */ -func findEasySolution(_ m: Int, _ n: Int) -> Int? { - if m == n { - return m - } - if m == 0 { - return n - } - if n == 0 { - return m - } - return nil -} - - -enum LCMError: Error { - case divisionByZero -} - -/* - Calculates the lcm for two given numbers using a specified gcd algorithm. - - - Parameter m: First natural number. - - Parameter n: Second natural number. - - Parameter using: The used gcd algorithm to calculate the lcm. - - Throws: Can throw a `divisionByZero` error if one of the given - attributes turns out to be zero or less. - - Returns: The least common multiplier of the two attributes as - an unsigned integer - */ -func lcm(_ m: Int, _ n: Int, using gcdAlgorithm: (Int, Int) -> (Int)) throws -> Int { - guard (m & n) != 0 else { throw LCMError.divisionByZero } - return m / gcdAlgorithm(m, n) * n -} - -gcdIterativeEuklid(52, 39) // 13 -gcdIterativeEuklid(228, 36) // 12 -gcdIterativeEuklid(51357, 3819) // 57 -gcdIterativeEuklid(841, 299) // 1 - -gcdRecursiveEuklid(52, 39) // 13 -gcdRecursiveEuklid(228, 36) // 12 -gcdRecursiveEuklid(51357, 3819) // 57 -gcdRecursiveEuklid(841, 299) // 1 +gcd(52, 39, using: gcdRecursiveEuklid) // 13 +gcd(228, 36, using: gcdRecursiveEuklid) // 12 +gcd(51357, 3819, using: gcdRecursiveEuklid) // 57 +gcd(841, 299, using: gcdRecursiveEuklid) // 1 -gcdBinaryRecursiveStein(52, 39) // 13 -gcdBinaryRecursiveStein(228, 36) // 12 -gcdBinaryRecursiveStein(51357, 3819) // 57 -gcdBinaryRecursiveStein(841, 299) // 1 +gcd(52, 39, using: gcdBinaryRecursiveStein) // 13 +gcd(228, 36, using: gcdBinaryRecursiveStein) // 12 +gcd(51357, 3819, using: gcdBinaryRecursiveStein) // 57 +gcd(841, 299, using: gcdBinaryRecursiveStein) // 1 do { - try lcm(2, 3, using: gcdIterativeEuklid) // 6 - try lcm(10, 8, using: gcdIterativeEuklid) // 40 + try lcm(2, 3) // 6 + try lcm(10, 8, using: gcdRecursiveEuklid) // 40 } catch { dump(error) } diff --git a/GCD/GCD.swift b/GCD/GCD.playground/Sources/GCD.swift similarity index 73% rename from GCD/GCD.swift rename to GCD/GCD.playground/Sources/GCD.swift index f4b390e63..4eb0c7621 100644 --- a/GCD/GCD.swift +++ b/GCD/GCD.playground/Sources/GCD.swift @@ -1,3 +1,17 @@ +/* + Finds the largest positive integer that divides both + m and n without a remainder. + + - Parameter m: First natural number + - Parameter n: Second natural number + - Parameter using: The used algorithm to calculate the gcd. + If nothing provided, the Iterative Euclidean + algorithm is used. + - Returns: The natural gcd of m and n. + */ +public func gcd(_ m: Int, _ n: Int, using gcdAlgorithm: (Int, Int) -> (Int) = gcdIterativeEuklid) -> Int { + return gcdAlgorithm(m, n) +} /* Iterative approach based on the Euclidean algorithm. @@ -6,9 +20,9 @@ is replaced by its difference with the smaller number. - Parameter m: First natural number - Parameter n: Second natural number - - Returns: The natural gcd if m and n + - Returns: The natural gcd of m and n. */ -func gcdIterativeEuklid(_ m: Int, _ n: Int) -> Int { +public func gcdIterativeEuklid(_ m: Int, _ n: Int) -> Int { var a: Int = 0 var b: Int = max(m, n) var r: Int = min(m, n) @@ -26,7 +40,7 @@ func gcdIterativeEuklid(_ m: Int, _ n: Int) -> Int { - Parameter m: First natural number - Parameter n: Second natural number - - Returns: The natural gcd of m and n + - Returns: The natural gcd of m and n. - Note: The recursive version makes only tail recursive calls. Most compilers for imperative languages do not optimize these. The swift compiler as well as the obj-c compiler is able to do @@ -34,7 +48,7 @@ func gcdIterativeEuklid(_ m: Int, _ n: Int) -> Int { up to be the same in terms of complexity. That said, tail call elimination is not mutually exclusive to recursion. */ -func gcdRecursiveEuklid(_ m: Int, _ n: Int) -> Int { +public func gcdRecursiveEuklid(_ m: Int, _ n: Int) -> Int { let r: Int = m % n if r != 0 { return gcdRecursiveEuklid(n, r) @@ -59,7 +73,7 @@ func gcdRecursiveEuklid(_ m: Int, _ n: Int) -> Int { the subtract and shift operations take linear time for very large integers */ -func gcdBinaryRecursiveStein(_ m: Int, _ n: Int) -> Int { +public func gcdBinaryRecursiveStein(_ m: Int, _ n: Int) -> Int { if let easySolution = findEasySolution(m, n) { return easySolution } if (m & 1) == 0 { @@ -85,6 +99,9 @@ func gcdBinaryRecursiveStein(_ m: Int, _ n: Int) -> Int { /* Finds an easy solution for the gcd. + - Parameter m: First natural number + - Parameter n: Second natural number + - Returns: A natural gcd of m and n if possible. - Note: It might be relevant for different usecases to try finding an easy solution for the GCD calculation before even starting more difficult operations. @@ -103,7 +120,7 @@ func findEasySolution(_ m: Int, _ n: Int) -> Int? { } -enum LCMError: Error { +public enum LCMError: Error { case divisionByZero } @@ -113,12 +130,14 @@ enum LCMError: Error { - Parameter m: First natural number. - Parameter n: Second natural number. - Parameter using: The used gcd algorithm to calculate the lcm. + If nothing provided, the Iterative Euclidean + algorithm is used. - Throws: Can throw a `divisionByZero` error if one of the given attributes turns out to be zero or less. - Returns: The least common multiplier of the two attributes as an unsigned integer */ -func lcm(_ m: Int, _ n: Int, using gcdAlgorithm: (Int, Int) -> (Int)) throws -> Int { - guard (m & n) != 0 else { throw LCMError.divisionByZero } +public func lcm(_ m: Int, _ n: Int, using gcdAlgorithm: (Int, Int) -> (Int) = gcdIterativeEuklid) throws -> Int { + guard m & n != 0 else { throw LCMError.divisionByZero } return m / gcdAlgorithm(m, n) * n } diff --git a/GCD/README.markdown b/GCD/README.markdown index a23aea190..07a3f0f4d 100644 --- a/GCD/README.markdown +++ b/GCD/README.markdown @@ -1,14 +1,19 @@ # Greatest Common Divisor The *greatest common divisor* (or Greatest Common Factor) of two numbers `a` and `b` is the largest positive integer that divides both `a` and `b` without a remainder. The GCD.swift file contains three different algorithms of how to calculate the greatest common divisor. +For example, `gcd(39, 52) = 13` because 13 divides 39 (`39 / 13 = 3`) as well as 52 (`52 / 13 = 4`). But there is no larger number than 13 that divides them both. +You've probably had to learn about this in school at some point. :-) -For example, `gcdIterativeEuklid(39, 52) = 13` because 13 divides 39 (`39/13 = 3`) as well as 52 (`52/13 = 4`). But there is no larger number than 13 that divides them both. +You probably won't need to use the GCD or LCM in any real-world problems, but it's cool to play around with this ancient algorithm. It was first described by Euklid in his [Elements](http://publicdomainreview.org/collections/the-first-six-books-of-the-elements-of-euclid-1847/) around 300 BC. Rumor has it that he discovered this algorithm while he was hacking on his Commodore 64. -You've probably had to learn about this in school at some point. :-) +## Different Algorithms -The laborious way to find the GCD of two numbers is to first figure out the factors of both numbers, then take the greatest number they have in common. The problem is that factoring numbers is quite difficult, especially when they get larger. (On the plus side, that difficulty is also what keeps your online payments secure.) +This example includes three different algorithms to find the same result. -There is a smarter way to calculate the GCD: Euclid's algorithm. The big idea here is that, +### Iterative Euklidean + +The laborious way to find the GCD of two numbers is to first figure out the factors of both numbers, then take the greatest number they have in common. The problem is that factoring numbers is quite difficult, especially when they get larger. (On the plus side, that difficulty is also what keeps your online payments secure.) +There is a smarter way to calculate the GCD: Euklid's algorithm. The big idea here is that, gcd(a, b) = gcd(b, a % b) @@ -16,6 +21,33 @@ where `a % b` calculates the remainder of `a` divided by `b`. Here is an implementation of this idea in Swift: +```swift +func gcdIterativeEuklid(_ m: Int, _ n: Int) -> Int { + var a: Int = 0 + var b: Int = max(m, n) + var r: Int = min(m, n) + + while r != 0 { + a = b + b = r + r = a % b + } + return b +} +``` + +Put it in a playground and try it out with these examples: + +```swift +gcd(52, 39, using: gcdIterativeEuklid) // 13 +gcd(228, 36, using: gcdIterativeEuklid) // 12 +gcd(51357, 3819, using: gcdIterativeEuklid) // 57 +``` + +### Recursive Euklidean + +Here is a slightly different implementation of Euklid's algorithm. Unlike the first version this doesn't use a `while` loop, but leverages recursion. + ```swift func gcdRecursiveEuklid(_ m: Int, _ n: Int) -> Int { let r: Int = m % n @@ -27,19 +59,21 @@ func gcdRecursiveEuklid(_ m: Int, _ n: Int) -> Int { } ``` -Put it in a playground and try it out with these examples: +Put it in a playground and compare it with the results of the iterative Eulidean gcd. They should return the same results: ```swift -gcdBinaryRecursiveStein(52, 39) // 13 -gcdRecursiveEuklid(228, 36) // 12 -gcdIterativeEuklid(51357, 3819) // 57 +gcd(52, 39, using: gcdRecursiveEuklid) // 13 +gcd(228, 36, using: gcdRecursiveEuklid) // 12 +gcd(51357, 3819, using: gcdRecursiveEuklid) // 57 ``` -Let's step through the third example using gcd as a representation of the gcdRecursiveEuklid here: +The `max()` and `min()` at the top of the function make sure we always divide the larger number by the smaller one. + +Let's step through the third example using the *recursive Euklidean algorithm* here: gcd(51357, 3819) -According to Euclid's rule, this is equivalent to, +According to Euklid's rule, this is equivalent to, gcd(3819, 51357 % 3819) = gcd(3819, 1710) @@ -57,7 +91,7 @@ And now can't divide any further. The remainder of `114 / 57` is zero because `1 gcd(3819, 51357) = gcd(57, 0) = 57 -So in each step of Euclid's algorithm the numbers become smaller and at some point it ends when one of them becomes zero. +So in each step of Euklid's algorithm the numbers become smaller and at some point it ends when one of them becomes zero. By the way, it's also possible that two numbers have a GCD of 1. They are said to be *relatively prime*. This happens when there is no number that divides them both, for example: @@ -65,55 +99,95 @@ By the way, it's also possible that two numbers have a GCD of 1. They are said t gcd(841, 299) // 1 ``` -Here is a slightly different implementation of Euclid's algorithm. Unlike the first version this doesn't use recursion but only a basic `while` loop. +### Binary Recursive Stein + +The binary GCD algorithm, also known as Stein's algorithm, is an algorithm that computes the greatest common divisor of two nonnegative integers. Stein's algorithm is very similar to the recursive Eulidean algorithm, but uses arithmetical operations, which are simpler for computers to perform, than the conventional Euclidean algorithm does. It replaces division with arithmetic shifts, comparisons, and subtraction. ```swift -func gcdIterativeEuklid(_ m: Int, _ n: Int) -> Int { - var a: Int = 0 - var b: Int = max(m, n) - var r: Int = min(m, n) +func gcdBinaryRecursiveStein(_ m: Int, _ n: Int) -> Int { + if let easySolution = findEasySolution(m, n) { return easySolution } + + if (m & 1) == 0 { + // m is even + if (n & 1) == 1 { + // and n is odd + return gcdBinaryRecursiveStein(m >> 1, n) + } else { + // both m and n are even + return gcdBinaryRecursiveStein(m >> 1, n >> 1) << 1 + } + } else if (n & 1) == 0 { + // m is odd, n is even + return gcdBinaryRecursiveStein(m, n >> 1) + } else if (m > n) { + // reduce larger argument + return gcdBinaryRecursiveStein((m - n) >> 1, n) + } else { + // reduce larger argument + return gcdBinaryRecursiveStein((n - m) >> 1, m) + } +} +``` - while r != 0 { - a = b - b = r - r = a % b +Depending on your application and your input expectations, it might be reasonable to also search for an "easy solution" using the other gcd implementations: + +```swift +func findEasySolution(_ m: Int, _ n: Int) -> Int? { + if m == n { + return m } - return b + if m == 0 { + return n + } + if n == 0 { + return m + } + return nil } + ``` -The `max()` and `min()` at the top of the function make sure we always divide the larger number by the smaller one. +Put it in a playground and compare it with the results of the other gcd implementations: + +```swift +gcd(52, 39, using: gcdBinaryRecursiveStein) // 13 +gcd(228, 36, using: gcdBinaryRecursiveStein) // 12 +gcd(51357, 3819, using: gcdBinaryRecursiveStein) // 57 +``` -## Least Common Multiple +### Least Common Multiple -An idea related to the GCD is the *least common multiple* or LCM. +Another algorithm related to the GCD is the *least common multiple* or LCM. -The least common multiple of two numbers `a` and `b` is the smallest positive integer that is a multiple of both. In other words, the LCM is evenly divisible by `a` and `b`. The example implementation of the LCM takes two numbers and a specification which GCD algorithm is used. +The least common multiple of two numbers `a` and `b` is the smallest positive integer that is a multiple of both. In other words, the LCM is evenly divisible by `a` and `b`. The example implementation of the LCM takes two numbers and an optional specification which GCD algorithm is used. -For example: `lcm(2, 3, using: gcdIterativeEuklid) = 6` because 6 can be divided by 2 and also by 3. +For example: `lcm(2, 3, using: gcdRecursiveEuklid) = 6` , which tells us that 6 is the smallest number that can be devided by 2 as well as 3. -We can calculate the LCM using Euclid's algorithm too: +We can calculate the LCM using Euklid's algorithm too: - a * b - lcm(a, b) = --------- - gcd(a, b) +a * b +lcm(a, b) = --------- +gcd(a, b) In code: ```swift -func lcm(_ m: Int, _ n: Int, using gcdAlgorithm: (Int, Int) -> (Int)) throws -> Int { - guard (m & n) != 0 else { throw LCMError.divisionByZero } - return m / gcdAlgorithm(m, n) * n +func lcm(_ m: Int, _ n: Int, using gcdAlgorithm: (Int, Int) -> (Int) = gcdIterativeEuklid) throws -> Int { +guard (m & n) != 0 else { throw LCMError.divisionByZero } +return m / gcdAlgorithm(m, n) * n } ``` And to try it out in a playground: ```swift -lcm(10, 8, using: gcdIterativeEuklid) // 40 +lcm(10, 8) // 40 ``` -You probably won't need to use the GCD or LCM in any real-world problems, but it's cool to play around with this ancient algorithm. It was first described by Euclid in his [Elements](http://publicdomainreview.org/collections/the-first-six-books-of-the-elements-of-euclid-1847/) around 300 BC. Rumor has it that he discovered this algorithm while he was hacking on his Commodore 64. +## Discussion + +While these algorithms all calculate the same result, comparing their plane complexity might not be enough to decide for one of them, though. The original iterative Euklidean algorithm is easier to understand. The recursive Euklidean and Stein's algorithm, while being generally faster, their runtime is heavily dependend on the environment they are running on. +_If a fast calculation of the gcd is necessary, a runtime comparison for the specific platform and compiler optimization level should be done for the rekursive Euklidean and Stein's algorithm._ *Written for Swift Algorithm Club by Matthijs Hollemans* -*Extended by Simon Krüger* \ No newline at end of file +*Extended by Simon C. Krüger* From 15f27793c56cd27788576deb0ef2c8ed901385d2 Mon Sep 17 00:00:00 2001 From: cr0ss Date: Fri, 11 Jan 2019 10:51:27 +0100 Subject: [PATCH 176/271] Linebreak in README --- GCD/README.markdown | 1 + 1 file changed, 1 insertion(+) diff --git a/GCD/README.markdown b/GCD/README.markdown index 07a3f0f4d..4c459eff0 100644 --- a/GCD/README.markdown +++ b/GCD/README.markdown @@ -190,4 +190,5 @@ While these algorithms all calculate the same result, comparing their plane comp _If a fast calculation of the gcd is necessary, a runtime comparison for the specific platform and compiler optimization level should be done for the rekursive Euklidean and Stein's algorithm._ *Written for Swift Algorithm Club by Matthijs Hollemans* + *Extended by Simon C. Krüger* From c5ff4084bd0f42ef7106a3139c217454aca28015 Mon Sep 17 00:00:00 2001 From: Richard Ash Date: Tue, 15 Jan 2019 15:27:38 -0800 Subject: [PATCH 177/271] Fix typo in Stack playground --- Stack/Stack.playground/Contents.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Stack/Stack.playground/Contents.swift b/Stack/Stack.playground/Contents.swift index 13774d7d1..e0632f8b4 100644 --- a/Stack/Stack.playground/Contents.swift +++ b/Stack/Stack.playground/Contents.swift @@ -45,7 +45,7 @@ public struct Stack { } /** - Removes and returns the item at the top of the sack. + Removes and returns the item at the top of the stack. - Returns: The item at the top of the stack. */ From 0f2e9e1ebc22de221f508504c6e10bd34a76d919 Mon Sep 17 00:00:00 2001 From: Mike Date: Mon, 28 Jan 2019 07:57:44 +0100 Subject: [PATCH 178/271] Update hyperlinks Link to author profiles were missing --- AVL Tree/README.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AVL Tree/README.markdown b/AVL Tree/README.markdown index e7515d99f..4e974ba71 100644 --- a/AVL Tree/README.markdown +++ b/AVL Tree/README.markdown @@ -88,4 +88,4 @@ The interesting bits are in the `balance()` method which is called after inserti AVL tree was the first self-balancing binary tree. These days, the [red-black tree](../Red-Black%20Tree/) seems to be more popular. -*Written for Swift Algorithm Club by Mike Taghavi and Matthijs Hollemans* +*Written for Swift Algorithm Club by [Mike Taghavi](https://github.com/mitghi) and [Matthijs Hollemans](https://github.com/hollance)* From ff780b6ff7d25b2aa79cbeef5ac72de6ce76b77e Mon Sep 17 00:00:00 2001 From: Richard Ash Date: Wed, 30 Jan 2019 17:16:49 -0800 Subject: [PATCH 179/271] Update README Updated supported Xcode version to 10 and swift version to 4.2 --- README.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.markdown b/README.markdown index ff8bfe778..88ea35949 100644 --- a/README.markdown +++ b/README.markdown @@ -8,7 +8,7 @@ If you're a computer science student who needs to learn this stuff for exams -- The goal of this project is to **explain how algorithms work**. The focus is on clarity and readability of the code, not on making a reusable library that you can drop into your own projects. That said, most of the code should be ready for production use but you may need to tweak it to fit into your own codebase. -Code is compatible with **Xcode 9** and **Swift 4**. We'll keep this updated with the latest version of Swift. +Code is compatible with **Xcode 10** and **Swift 4.2**. We'll keep this updated with the latest version of Swift. :heart_eyes: **Suggestions and contributions are welcome!** :heart_eyes: From fa656f090ec4de0b7c9e8bd8eeb2e808c3d7f32c Mon Sep 17 00:00:00 2001 From: Andriy Makukha Date: Fri, 1 Feb 2019 10:20:10 +0800 Subject: [PATCH 180/271] reserveCapacity was missing in README (11% faster with it) --- Merge Sort/README.markdown | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Merge Sort/README.markdown b/Merge Sort/README.markdown index 7ad6fd95e..d86f062f4 100644 --- a/Merge Sort/README.markdown +++ b/Merge Sort/README.markdown @@ -79,6 +79,7 @@ func merge(leftPile: [Int], rightPile: [Int]) -> [Int] { // 2 var orderedPile = [Int]() + orderedPile.reserveCapacity(leftPile.count + rightPile.count) // 3 while leftIndex < leftPile.count && rightIndex < rightPile.count { @@ -115,7 +116,7 @@ This method may look scary, but it is quite straightforward: 1. You need two indexes to keep track of your progress for the two arrays while merging. -2. This is the merged array. It is empty right now, but you will build it up in subsequent steps by appending elements from the other arrays. +2. This is the merged array. It is empty right now, but you will build it up in subsequent steps by appending elements from the other arrays. Since you already know number of elements that will end up in this array, you reserve capacity to avoid reallocation overhead later. 3. This while-loop will compare the elements from the left and right sides and append them into the `orderedPile` while making sure that the result stays in order. From d4b9091af6f83f55e9681a5a11b6374bd2ac8cff Mon Sep 17 00:00:00 2001 From: Morgan Davison Date: Sun, 3 Feb 2019 20:45:28 -0500 Subject: [PATCH 181/271] Check with Xcode 10.1 No changes needed --- 3Sum and 4Sum/3Sum.playground/Contents.swift | 4 ++++ .../playground.xcworkspace/contents.xcworkspacedata | 7 +++++++ .../xcshareddata/IDEWorkspaceChecks.plist | 8 ++++++++ 3Sum and 4Sum/4Sum.playground/Contents.swift | 5 +++++ .../playground.xcworkspace/contents.xcworkspacedata | 7 +++++++ .../xcshareddata/IDEWorkspaceChecks.plist | 8 ++++++++ 6 files changed, 39 insertions(+) create mode 100644 3Sum and 4Sum/3Sum.playground/playground.xcworkspace/contents.xcworkspacedata create mode 100644 3Sum and 4Sum/3Sum.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist create mode 100644 3Sum and 4Sum/4Sum.playground/playground.xcworkspace/contents.xcworkspacedata create mode 100644 3Sum and 4Sum/4Sum.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist diff --git a/3Sum and 4Sum/3Sum.playground/Contents.swift b/3Sum and 4Sum/3Sum.playground/Contents.swift index 2581da6e7..d172aed1f 100644 --- a/3Sum and 4Sum/3Sum.playground/Contents.swift +++ b/3Sum and 4Sum/3Sum.playground/Contents.swift @@ -1,3 +1,7 @@ +// last checked with Xcode 10.1 +#if swift(>=4.2) +print("Hello, Swift 4.2!") +#endif extension Collection where Element: Equatable { diff --git a/3Sum and 4Sum/3Sum.playground/playground.xcworkspace/contents.xcworkspacedata b/3Sum and 4Sum/3Sum.playground/playground.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..919434a62 --- /dev/null +++ b/3Sum and 4Sum/3Sum.playground/playground.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/3Sum and 4Sum/3Sum.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/3Sum and 4Sum/3Sum.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/3Sum and 4Sum/3Sum.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/3Sum and 4Sum/4Sum.playground/Contents.swift b/3Sum and 4Sum/4Sum.playground/Contents.swift index 86b530224..37f75918c 100644 --- a/3Sum and 4Sum/4Sum.playground/Contents.swift +++ b/3Sum and 4Sum/4Sum.playground/Contents.swift @@ -1,3 +1,8 @@ +// last checked with Xcode 10.1 +#if swift(>=4.2) +print("Hello, Swift 4.2!") +#endif + extension Collection where Element: Equatable { /// In a sorted collection, replaces the given index with a successor mapping to a unique element. diff --git a/3Sum and 4Sum/4Sum.playground/playground.xcworkspace/contents.xcworkspacedata b/3Sum and 4Sum/4Sum.playground/playground.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..919434a62 --- /dev/null +++ b/3Sum and 4Sum/4Sum.playground/playground.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/3Sum and 4Sum/4Sum.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/3Sum and 4Sum/4Sum.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/3Sum and 4Sum/4Sum.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + From 2f92aef01b0d7e6b57e4ae8a9de79467dd7598d9 Mon Sep 17 00:00:00 2001 From: Morgan Kan Date: Wed, 6 Feb 2019 21:34:53 +0000 Subject: [PATCH 182/271] fix bracket formatting --- Bit Set/BitSet.playground/Contents.swift | 14 +++++++------- Bit Set/BitSet.playground/Sources/BitSet.swift | 8 ++++---- Bit Set/BitSet.swift | 8 ++++---- 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/Bit Set/BitSet.playground/Contents.swift b/Bit Set/BitSet.playground/Contents.swift index 2c5edcd84..70d5ca5e8 100644 --- a/Bit Set/BitSet.playground/Contents.swift +++ b/Bit Set/BitSet.playground/Contents.swift @@ -93,8 +93,8 @@ z.all1() // false var smallBitSet = BitSet(size: 16) smallBitSet[5] = true smallBitSet[10] = true -print( smallBitSet >> 3 ) -print( smallBitSet << 6 ) // one bit shifts off the end +print(smallBitSet >> 3) +print(smallBitSet << 6) // one bit shifts off the end var bigBitSet = BitSet( size: 120 ) bigBitSet[1] = true @@ -104,8 +104,8 @@ bigBitSet[32] = true bigBitSet[55] = true bigBitSet[64] = true bigBitSet[80] = true -print( bigBitSet ) -print( bigBitSet << 32 ) -print( bigBitSet << 64 ) -print( bigBitSet >> 32 ) -print( bigBitSet >> 64 ) +print(bigBitSet) +print(bigBitSet << 32) +print(bigBitSet << 64) +print(bigBitSet >> 32) +print(bigBitSet >> 64) diff --git a/Bit Set/BitSet.playground/Sources/BitSet.swift b/Bit Set/BitSet.playground/Sources/BitSet.swift index 85f5da505..258bce457 100644 --- a/Bit Set/BitSet.playground/Sources/BitSet.swift +++ b/Bit Set/BitSet.playground/Sources/BitSet.swift @@ -235,10 +235,10 @@ public func << (lhs: BitSet, numBitsLeft: Int) -> BitSet { let shift = numBitsLeft % lhs.N for i in 0..= 0 ) { + if (i - offset >= 0) { out.words[i] = lhs.words[i - offset] << shift } - if( i - offset - 1 >= 0 ) { + if (i - offset - 1 >= 0) { out.words[i] |= lhs.words[i - offset - 1] >> (lhs.N - shift) } } @@ -253,10 +253,10 @@ public func >> (lhs: BitSet, numBitsRight: Int) -> BitSet { let shift = numBitsRight % lhs.N for i in 0..> shift } - if( i + offset + 1 < lhs.words.count ) { + if (i + offset + 1 < lhs.words.count) { out.words[i] |= lhs.words[i + offset + 1] << (lhs.N - shift) } } diff --git a/Bit Set/BitSet.swift b/Bit Set/BitSet.swift index 83829c6c5..19413f424 100644 --- a/Bit Set/BitSet.swift +++ b/Bit Set/BitSet.swift @@ -235,10 +235,10 @@ public func << (lhs: BitSet, numBitsLeft: Int) -> BitSet { let shift = numBitsLeft % lhs.N for i in 0..= 0 ) { + if (i - offset >= 0) { out.words[i] = lhs.words[i - offset] << shift } - if( i - offset - 1 >= 0 ) { + if (i - offset - 1 >= 0) { out.words[i] |= lhs.words[i - offset - 1] >> (lhs.N - shift) } } @@ -253,10 +253,10 @@ public func >> (lhs: BitSet, numBitsRight: Int) -> BitSet { let shift = numBitsRight % lhs.N for i in 0..> shift } - if( i + offset + 1 < lhs.words.count ) { + if (i + offset + 1 < lhs.words.count) { out.words[i] |= lhs.words[i + offset + 1] << (lhs.N - shift) } } From 27efddaa9ceaa4f1675dc69433d253ce028596f1 Mon Sep 17 00:00:00 2001 From: Larissa Laich Date: Thu, 7 Feb 2019 20:47:01 +0100 Subject: [PATCH 183/271] fixed error in linear regression formula --- Linear Regression/README.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Linear Regression/README.markdown b/Linear Regression/README.markdown index 4f9d030db..db04bf8a2 100644 --- a/Linear Regression/README.markdown +++ b/Linear Regression/README.markdown @@ -75,7 +75,7 @@ for _ in 1...numberOfIterations { The program loops through each data point (each car age and car price). For each data point it adjusts the intercept and the slope to bring them closer to the correct values. The equations used in the code to adjust the intercept and the slope are based on moving in the direction of the maximal reduction of these variables. This is a *gradient descent*. -We want to minimise the square of the distance between the line and the points. We define a function `J` which represents this distance - for simplicity we consider only one point here. This function `J` is proportional to `((slope.carAge + intercept) - carPrice)) ^ 2`. +We want to minimise the square of the distance between the line and the points. We define a function `J` which represents this distance - for simplicity we consider only one point here. This function `J` is proportional to `((slope * carAge + intercept) - carPrice)) ^ 2`. In order to move in the direction of maximal reduction, we take the partial derivative of this function with respect to the slope, and similarly for the intercept. We multiply these derivatives by our factor alpha and then use them to adjust the values of slope and intercept on each iteration. From 6d936e461435783e2a19afcf6b817e1b9c0ceb5f Mon Sep 17 00:00:00 2001 From: Richard Ash Date: Tue, 12 Feb 2019 14:38:02 +0530 Subject: [PATCH 184/271] Update Karatsuba README --- Karatsuba Multiplication/README.markdown | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Karatsuba Multiplication/README.markdown b/Karatsuba Multiplication/README.markdown index aef0d744a..02e54a1bf 100644 --- a/Karatsuba Multiplication/README.markdown +++ b/Karatsuba Multiplication/README.markdown @@ -115,10 +115,10 @@ What about the running time of this algorithm? Is all this extra work worth it? ## Resources -[Wikipedia] (https://en.wikipedia.org/wiki/Karatsuba_algorithm) +[Wikipedia](https://en.wikipedia.org/wiki/Karatsuba_algorithm) -[WolframMathWorld] (http://mathworld.wolfram.com/KaratsubaMultiplication.html) +[WolframMathWorld](http://mathworld.wolfram.com/KaratsubaMultiplication.html) -[Master Theorem] (https://en.wikipedia.org/wiki/Master_theorem) +[Master Theorem](https://en.wikipedia.org/wiki/Master_theorem) *Written for Swift Algorithm Club by Richard Ash* From deae79c2010d1e7341b24314819c9736cdfc4387 Mon Sep 17 00:00:00 2001 From: Richard Ash Date: Tue, 12 Feb 2019 15:07:50 +0530 Subject: [PATCH 185/271] Update README Replace "minimise" with "minimize" --- Linear Regression/README.markdown | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Linear Regression/README.markdown b/Linear Regression/README.markdown index db04bf8a2..d07bf1497 100644 --- a/Linear Regression/README.markdown +++ b/Linear Regression/README.markdown @@ -21,7 +21,7 @@ Let's start by looking at the data plotted out: We could imagine a straight line drawn through the points on this graph. It's not (in this case) going to go exactly through every point, but we could place the line so that it goes as close to all the points as possible. -To say this in another way, we want to make the distance from the line to each point as small as possible. This is most often done by minimising the square of the distance from the line to each point. +To say this in another way, we want to make the distance from the line to each point as small as possible. This is most often done by minimizing the square of the distance from the line to each point. We can describe the straight line in terms of two variables: @@ -75,7 +75,7 @@ for _ in 1...numberOfIterations { The program loops through each data point (each car age and car price). For each data point it adjusts the intercept and the slope to bring them closer to the correct values. The equations used in the code to adjust the intercept and the slope are based on moving in the direction of the maximal reduction of these variables. This is a *gradient descent*. -We want to minimise the square of the distance between the line and the points. We define a function `J` which represents this distance - for simplicity we consider only one point here. This function `J` is proportional to `((slope * carAge + intercept) - carPrice)) ^ 2`. +We want to minimize the square of the distance between the line and the points. We define a function `J` which represents this distance - for simplicity we consider only one point here. This function `J` is proportional to `((slope * carAge + intercept) - carPrice)) ^ 2`. In order to move in the direction of maximal reduction, we take the partial derivative of this function with respect to the slope, and similarly for the intercept. We multiply these derivatives by our factor alpha and then use them to adjust the values of slope and intercept on each iteration. From a88c984a388c456de27302af796180bf25b15529 Mon Sep 17 00:00:00 2001 From: Morgan Kan Date: Fri, 15 Feb 2019 18:19:58 +0000 Subject: [PATCH 186/271] remove duplicate source file, update README --- Bit Set/BitSet.swift | 293 ---------------------------------------- Bit Set/README.markdown | 84 ++++++++++++ 2 files changed, 84 insertions(+), 293 deletions(-) delete mode 100644 Bit Set/BitSet.swift diff --git a/Bit Set/BitSet.swift b/Bit Set/BitSet.swift deleted file mode 100644 index 19413f424..000000000 --- a/Bit Set/BitSet.swift +++ /dev/null @@ -1,293 +0,0 @@ -/* - A fixed-size sequence of n bits. Bits have indices 0 to n-1. - */ -public struct BitSet { - /* How many bits this object can hold. */ - private(set) public var size: Int - - /* - We store the bits in a list of unsigned 64-bit integers. - The first entry, `words[0]`, is the least significant word. - */ - fileprivate let N = 64 - public typealias Word = UInt64 - fileprivate(set) public var words: [Word] - - private let allOnes = ~Word() - - /* Creates a bit set that can hold `size` bits. All bits are initially 0. */ - public init(size: Int) { - precondition(size > 0) - self.size = size - - // Round up the count to the next multiple of 64. - let n = (size + (N-1)) / N - words = [Word](repeating: 0, count: n) - } - - /* Converts a bit index into an array index and a mask inside the word. */ - private func indexOf(_ i: Int) -> (Int, Word) { - precondition(i >= 0) - precondition(i < size) - let o = i / N - let m = Word(i - o*N) - return (o, 1 << m) - } - - /* Returns a mask that has 1s for all bits that are in the last word. */ - private func lastWordMask() -> Word { - let diff = words.count*N - size - if diff > 0 { - // Set the highest bit that's still valid. - let mask = 1 << Word(63 - diff) - // Subtract 1 to turn it into a mask, and add the high bit back in. - return (Word)(mask | (mask - 1)) - } else { - return allOnes - } - } - - /* - If the size is not a multiple of N, then we have to clear out the bits - that we're not using, or bitwise operations between two differently sized - BitSets will go wrong. - */ - fileprivate mutating func clearUnusedBits() { - words[words.count - 1] &= lastWordMask() - } - - /* So you can write bitset[99] = ... */ - public subscript(i: Int) -> Bool { - get { return isSet(i) } - set { if newValue { set(i) } else { clear(i) } } - } - - /* Sets the bit at the specified index to 1. */ - public mutating func set(_ i: Int) { - let (j, m) = indexOf(i) - words[j] |= m - } - - /* Sets all the bits to 1. */ - public mutating func setAll() { - for i in 0.. Bool { - let (j, m) = indexOf(i) - words[j] ^= m - return (words[j] & m) != 0 - } - - /* Determines whether the bit at the specific index is 1 (true) or 0 (false). */ - public func isSet(_ i: Int) -> Bool { - let (j, m) = indexOf(i) - return (words[j] & m) != 0 - } - - /* - Returns the number of bits that are 1. Time complexity is O(s) where s is - the number of 1-bits. - */ - public var cardinality: Int { - var count = 0 - for var x in words { - while x != 0 { - let y = x & ~(x - 1) // find lowest 1-bit - x = x ^ y // and erase it - count += 1 - } - } - return count - } - - /* Checks if all the bits are set. */ - public func all1() -> Bool { - for i in 0.. Bool { - for x in words { - if x != 0 { return true } - } - return false - } - - /* Checks if none of the bits are set. */ - public func all0() -> Bool { - for x in words { - if x != 0 { return false } - } - return true - } -} - -// MARK: - Equality - -extension BitSet: Equatable { -} - -public func == (lhs: BitSet, rhs: BitSet) -> Bool { - return lhs.words == rhs.words -} - -// MARK: - Hashing - -extension BitSet: Hashable { - /* Based on the hashing code from Java's BitSet. */ - public var hashValue: Int { - var h = Word(1234) - for i in stride(from: words.count, to: 0, by: -1) { - h ^= words[i - 1] &* Word(i) - } - return Int((h >> 32) ^ h) - } -} - -// MARK: - Bitwise operations - -extension BitSet { - public static var allZeros: BitSet { - return BitSet(size: 64) - } -} - -private func copyLargest(_ lhs: BitSet, _ rhs: BitSet) -> BitSet { - return (lhs.words.count > rhs.words.count) ? lhs : rhs -} - -/* - Note: In all of these bitwise operations, lhs and rhs are allowed to have a - different number of bits. The new BitSet always has the larger size. - The extra bits that get added to the smaller BitSet are considered to be 0. - That will strip off the higher bits from the larger BitSet when doing &. - */ - -public func & (lhs: BitSet, rhs: BitSet) -> BitSet { - let m = max(lhs.size, rhs.size) - var out = BitSet(size: m) - let n = min(lhs.words.count, rhs.words.count) - for i in 0.. BitSet { - var out = copyLargest(lhs, rhs) - let n = min(lhs.words.count, rhs.words.count) - for i in 0.. BitSet { - var out = copyLargest(lhs, rhs) - let n = min(lhs.words.count, rhs.words.count) - for i in 0.. BitSet { - var out = BitSet(size: rhs.size) - for i in 0.. BitSet { - var out = lhs - let offset = numBitsLeft / lhs.N - let shift = numBitsLeft % lhs.N - for i in 0..= 0) { - out.words[i] = lhs.words[i - offset] << shift - } - if (i - offset - 1 >= 0) { - out.words[i] |= lhs.words[i - offset - 1] >> (lhs.N - shift) - } - } - - out.clearUnusedBits() - return out -} - -public func >> (lhs: BitSet, numBitsRight: Int) -> BitSet { - var out = lhs - let offset = numBitsRight / lhs.N - let shift = numBitsRight % lhs.N - for i in 0..> shift - } - if (i + offset + 1 < lhs.words.count) { - out.words[i] |= lhs.words[i + offset + 1] << (lhs.N - shift) - } - } - - out.clearUnusedBits() - return out -} - - -// MARK: - Debugging - -extension UInt64 { - /* Writes the bits in little-endian order, LSB first. */ - public func bitsToString() -> String { - var s = "" - var n = self - for _ in 1...64 { - s += ((n & 1 == 1) ? "1" : "0") - n >>= 1 - } - return s - } -} - -extension BitSet: CustomStringConvertible { - public var description: String { - var s = "" - for x in words { - s += x.bitsToString() + " " - } - return s - } -} - diff --git a/Bit Set/README.markdown b/Bit Set/README.markdown index 6bb6e7c89..365950d06 100644 --- a/Bit Set/README.markdown +++ b/Bit Set/README.markdown @@ -329,6 +329,90 @@ This is the original value but with the lowest 1-bit removed. We keep repeating this process until the value consists of all zeros. The time complexity is **O(s)** where **s** is the number of 1-bits. +## Bit Shift Operations + +Bit shifts are a common and very useful mechanism when dealing with bitsets. Here is the right-shift function: + +``` +public func >> (lhs: BitSet, numBitsRight: Int) -> BitSet { + var out = lhs + let offset = numBitsRight / lhs.N + let shift = numBitsRight % lhs.N + for i in 0..> shift + } + + if (i + offset + 1 < lhs.words.count) { + out.words[i] |= lhs.words[i + offset + 1] << (lhs.N - shift) + } + } + + out.clearUnusedBits() + return out +} +``` + +Let's start with this line: + +```swift +for i in 0..> 10 + +I've grouped each part of the number by word to make it easier to see what happens. The for-loop goes from least significant word to most significant. So for index zero we're want to know what bits will make up our least significant word. Let's calculate our offset and shift values: + + offset = 10 / 8 = 1 (remember this is integer division) + shift = 10 % 8 = 2 + +So we consult the word at offset 1 to get some of our bits: + + 11000000 >> 2 = 00110000 + +And we get the rest of them from the word one further away: + + 01000010 << (8 - 2) = 10000000 + +And we bitwise OR these together to get our least significant term + + 00110000 + 10000000 + -------- OR + 10110000 + +We repeat this for the 2nd least significant term and obtain: + + 00010000 + +The last term can't get any bits because they are past the end of our number so those are all zeros. Our result is: + + 00000000 00010000 10110000 + ## See also [Bit Twiddling Hacks](http://graphics.stanford.edu/~seander/bithacks.html) From a10a15bab9934520d1762b5a71f357e6b112bc2a Mon Sep 17 00:00:00 2001 From: Morgan Kan Date: Sat, 16 Feb 2019 09:49:47 +0000 Subject: [PATCH 187/271] remove reference to old source file --- swift-algorithm-club.xcworkspace/contents.xcworkspacedata | 3 --- 1 file changed, 3 deletions(-) diff --git a/swift-algorithm-club.xcworkspace/contents.xcworkspacedata b/swift-algorithm-club.xcworkspace/contents.xcworkspacedata index a37dac494..12be3d827 100644 --- a/swift-algorithm-club.xcworkspace/contents.xcworkspacedata +++ b/swift-algorithm-club.xcworkspace/contents.xcworkspacedata @@ -549,9 +549,6 @@ - - From aa2a318bfbf24223a26a609d8a23dba3accba935 Mon Sep 17 00:00:00 2001 From: Jawwad Ahmad Date: Sun, 24 Feb 2019 14:53:47 -0800 Subject: [PATCH 188/271] [Swift 4.2] Update All-Pairs Shortest Paths to Swift 4.2 --- .../APSP/APSP.playground/Contents.swift | 5 ---- .../APSP.playground/contents.xcplayground | 2 +- .../APSP/APSP.xcodeproj/project.pbxproj | 26 ++++++++++++++----- .../xcshareddata/xcschemes/APSP.xcscheme | 2 +- .../xcshareddata/xcschemes/APSPTests.xcscheme | 2 +- .../xcshareddata/IDEWorkspaceChecks.plist | 8 ++++++ .../APSP/APSPTests/APSPTests.swift | 8 ------ .../xcshareddata/xcschemes/Graph.xcscheme | 2 +- .../xcschemes/GraphTests.xcscheme | 2 +- 9 files changed, 33 insertions(+), 24 deletions(-) create mode 100644 All-Pairs Shortest Paths/APSP/APSP.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist diff --git a/All-Pairs Shortest Paths/APSP/APSP.playground/Contents.swift b/All-Pairs Shortest Paths/APSP/APSP.playground/Contents.swift index b1b499b39..24c27cac8 100644 --- a/All-Pairs Shortest Paths/APSP/APSP.playground/Contents.swift +++ b/All-Pairs Shortest Paths/APSP/APSP.playground/Contents.swift @@ -1,10 +1,5 @@ //: Playground - noun: a place where people can play -// last checked with Xcode 9.0b4 -#if swift(>=4.0) -print("Hello, Swift 4!") -#endif - import Graph import APSP diff --git a/All-Pairs Shortest Paths/APSP/APSP.playground/contents.xcplayground b/All-Pairs Shortest Paths/APSP/APSP.playground/contents.xcplayground index 06828af92..d5a8d0e3f 100644 --- a/All-Pairs Shortest Paths/APSP/APSP.playground/contents.xcplayground +++ b/All-Pairs Shortest Paths/APSP/APSP.playground/contents.xcplayground @@ -1,4 +1,4 @@ - + \ No newline at end of file diff --git a/All-Pairs Shortest Paths/APSP/APSP.xcodeproj/project.pbxproj b/All-Pairs Shortest Paths/APSP/APSP.xcodeproj/project.pbxproj index 908d32785..dc8e509a1 100644 --- a/All-Pairs Shortest Paths/APSP/APSP.xcodeproj/project.pbxproj +++ b/All-Pairs Shortest Paths/APSP/APSP.xcodeproj/project.pbxproj @@ -187,12 +187,12 @@ isa = PBXProject; attributes = { LastSwiftUpdateCheck = 0730; - LastUpgradeCheck = 0820; + LastUpgradeCheck = 1010; ORGANIZATIONNAME = "Swift Algorithm Club"; TargetAttributes = { 493D8DDF1CDD2A1C0089795A = { CreatedOnToolsVersion = 7.3; - LastSwiftMigration = 0820; + LastSwiftMigration = 1010; }; 493D8DF01CDD5B960089795A = { CreatedOnToolsVersion = 7.3; @@ -302,14 +302,22 @@ CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; @@ -349,14 +357,22 @@ CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; @@ -388,7 +404,7 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "com.swift-algorithm-club.APSPTests"; PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 4.0; + SWIFT_VERSION = 4.2; }; name = Debug; }; @@ -400,7 +416,7 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "com.swift-algorithm-club.APSPTests"; PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 4.0; + SWIFT_VERSION = 4.2; }; name = Release; }; @@ -420,7 +436,6 @@ PRODUCT_BUNDLE_IDENTIFIER = "com.swift-algorithm-club.APSP"; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; - SWIFT_SWIFT3_OBJC_INFERENCE = On; SWIFT_VERSION = 4.2; VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; @@ -443,7 +458,6 @@ PRODUCT_BUNDLE_IDENTIFIER = "com.swift-algorithm-club.APSP"; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; - SWIFT_SWIFT3_OBJC_INFERENCE = On; SWIFT_VERSION = 4.2; VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; diff --git a/All-Pairs Shortest Paths/APSP/APSP.xcodeproj/xcshareddata/xcschemes/APSP.xcscheme b/All-Pairs Shortest Paths/APSP/APSP.xcodeproj/xcshareddata/xcschemes/APSP.xcscheme index e313c4b88..944957d8f 100644 --- a/All-Pairs Shortest Paths/APSP/APSP.xcodeproj/xcshareddata/xcschemes/APSP.xcscheme +++ b/All-Pairs Shortest Paths/APSP/APSP.xcodeproj/xcshareddata/xcschemes/APSP.xcscheme @@ -1,6 +1,6 @@ + + + + IDEDidComputeMac32BitWarning + + + diff --git a/All-Pairs Shortest Paths/APSP/APSPTests/APSPTests.swift b/All-Pairs Shortest Paths/APSP/APSPTests/APSPTests.swift index c2f64e239..ce0dfcf32 100644 --- a/All-Pairs Shortest Paths/APSP/APSPTests/APSPTests.swift +++ b/All-Pairs Shortest Paths/APSP/APSPTests/APSPTests.swift @@ -19,14 +19,6 @@ struct TestCase where T: Hashable { } class APSPTests: XCTestCase { - - func testSwift4() { - // last checked with Xcode 9.0b4 - #if swift(>=4.0) - print("Hello, Swift 4!") - #endif - } - /** See Figure 25.1 of “Introduction to Algorithms” by Cormen et al, 3rd ed., pg 690 */ diff --git a/Graph/Graph.xcodeproj/xcshareddata/xcschemes/Graph.xcscheme b/Graph/Graph.xcodeproj/xcshareddata/xcschemes/Graph.xcscheme index 73524effc..84c688e66 100644 --- a/Graph/Graph.xcodeproj/xcshareddata/xcschemes/Graph.xcscheme +++ b/Graph/Graph.xcodeproj/xcshareddata/xcschemes/Graph.xcscheme @@ -1,6 +1,6 @@ Date: Mon, 25 Feb 2019 22:08:56 +0900 Subject: [PATCH 189/271] Fix wrong description Signed-off-by: bbvch13531 --- Linked List/LinkedList.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Linked List/LinkedList.swift b/Linked List/LinkedList.swift index 7c2cbb3b1..de8a42c93 100755 --- a/Linked List/LinkedList.swift +++ b/Linked List/LinkedList.swift @@ -67,7 +67,7 @@ public final class LinkedList { /// - Returns: LinkedListNode public func node(at index: Int) -> Node { assert(head != nil, "List is empty") - assert(index >= 0, "index must be greater than 0") + assert(index >= 0, "index must be greater or equal to 0") if index == 0 { return head! From 8a6d99aa19f0888b51969bc10c0463aa98c1a94e Mon Sep 17 00:00:00 2001 From: bbvch13531 Date: Mon, 25 Feb 2019 22:09:44 +0900 Subject: [PATCH 190/271] Fix typo Signed-off-by: bbvch13531 --- Insertion Sort/InsertionSort.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Insertion Sort/InsertionSort.swift b/Insertion Sort/InsertionSort.swift index 9faf9dc42..2ad607ac8 100644 --- a/Insertion Sort/InsertionSort.swift +++ b/Insertion Sort/InsertionSort.swift @@ -22,7 +22,7 @@ func insertionSort(_ array: [T], _ isOrderedBefore: (T, T) -> Bool) -> [T] { /// Performs the Insertion sort algorithm to a given array /// -/// - Parameter array: the array to be sorted, conatining elements that conform to the Comparable protocol +/// - Parameter array: the array to be sorted, containing elements that conform to the Comparable protocol /// - Returns: a sorted array containing the same elements func insertionSort(_ array: [T]) -> [T] { guard array.count > 1 else { return array } From de935b700ab32492791dbd9771a3fc841ad4044c Mon Sep 17 00:00:00 2001 From: Kelvin Lau Date: Tue, 5 Mar 2019 22:37:29 -0500 Subject: [PATCH 191/271] Updates README.markdown * now using new `random` API from the Swift collection protocols, instead of creating a new function that uses `arc4random` * updates code to Swift 4.2 * fixes some inconsistencies between terms begin used - such as `MAX_GENERATIONS` and `GENERATIONS` --- Genetic/README.markdown | 60 ++++++++++++++++------------------------- 1 file changed, 23 insertions(+), 37 deletions(-) diff --git a/Genetic/README.markdown b/Genetic/README.markdown index 18afb9639..5dc4747f2 100644 --- a/Genetic/README.markdown +++ b/Genetic/README.markdown @@ -5,7 +5,7 @@ A genetic algorithm (GA) is process inspired by natural selection to find high quality solutions. Most commonly used for optimization. GAs rely on the bio-inspired processes of natural selection, more specifically the process of selection (fitness), crossover and mutation. To understand more, let's walk through these processes in terms of biology: ### Selection ->**Selection**, in biology, the preferential survival and reproduction or preferential elimination of individuals with certain genotypes (genetic compositions), by means of natural or artificial controlling factors. [Britannica](britannica) +>**Selection**, in biology, the preferential survival and reproduction or preferential elimination of individuals with certain genotypes (genetic compositions), by means of natural or artificial controlling factors. In other words, survival of the fittest. Organisms that survive in their environment tend to reproduce more. With GAs we generate a fitness model that will rank individuals and give them a better chance for reproduction. @@ -60,35 +60,23 @@ extension String { let OPTIMAL:[UInt8] = "Hello, World".unicodeArray let DNA_SIZE = OPTIMAL.count let POP_SIZE = 50 -let MAX_GENERATIONS = 5000 +let GENERATIONS = 5000 let MUTATION_CHANCE = 100 ``` - The last piece we need for set up is a function to give us a random unicode value from our lexicon: - - ```swift - func randomChar(from lexicon: [UInt8]) -> UInt8 { - let len = UInt32(lexicon.count-1) - let rand = Int(arc4random_uniform(len)) - return lexicon[rand] - } - ``` - - **Note**: `arc4random_uniform` is strictly used in this example. It would be fun to play around with some of the [randomization in GameKit](https://developer.apple.com/library/content/documentation/General/Conceptual/GameplayKit_Guide/RandomSources.html) - ### Population Zero Before selecting, crossover and mutation, we need a population to start with. Now that we have the universe defined we can write that function: ```swift func randomPopulation(from lexicon: [UInt8], populationSize: Int, dnaSize: Int) -> [[UInt8]] { - + guard lexicon.count > 1 else { return [] } var pop = [[UInt8]]() (0.. Int { +func calculateFitness(dna: [UInt8], optimal: [UInt8]) -> Int { + guard dna.count == optimal.count else { return -1 } var fitness = 0 - (0...dna.count-1).forEach { c in - fitness += abs(Int(dna[c]) - Int(optimal[c])) + for index in dna.indices { + fitness += abs(Int(dna[index]) - Int(optimal[index])) } return fitness } @@ -121,13 +110,11 @@ Let's take a second and ask why on this one. Why would you not always want to se With all that, here is our weight choice function: -```swift -func weightedChoice(items:[(dna:[UInt8], weight:Double)]) -> (dna:[UInt8], weight:Double) { - - let total = items.reduce(0.0) { return $0 + $1.weight} - - var n = Double(arc4random_uniform(UInt32(total * 1000000.0))) / 1000000.0 - +func weightedChoice(items: [(dna: [UInt8], weight: Double)]) -> (dna: [UInt8], weight: Double) { + + let total = items.reduce(0) { $0 + $1.weight } + var n = Double.random(in: 0..<(total * 1000000)) / 1000000.0 + for item in items { if n < item.weight { return item @@ -136,25 +123,24 @@ func weightedChoice(items:[(dna:[UInt8], weight:Double)]) -> (dna:[UInt8], weigh } return items[1] } -``` -The above function takes a list of individuals with their calculated fitness. Then selects one at random offset by their fitness value. The horrible 1,000,000 multiplication and division is to insure precision by calculating decimals. `arc4random` only uses integers so this is required to convert to a precise Double, it's not perfect, but enough for our example. + +The above function takes a list of individuals with their calculated fitness. Then selects one at random offset by their fitness value. The horrible 1,000,000 multiplication and division is to insure precision by calculating decimals. `Double.random` only uses integers so this is required to convert to a precise Double, it's not perfect, but enough for our example. ## Mutation The all powerful mutation, the thing that introduces otherwise non existent fitness variance. It can either hurt of improve a individuals fitness but over time it will cause evolution towards more fit populations. Imagine if our initial random population was missing the charachter `H`, in that case we need to rely on mutation to introduce that character into the population in order to achieve the optimal solution. ```swift -func mutate(lexicon: [UInt8], dna:[UInt8], mutationChance:Int) -> [UInt8] { +func mutate(lexicon: [UInt8], dna: [UInt8], mutationChance: Int) -> [UInt8] { var outputDna = dna - (0.. [UInt8] { - let pos = Int(arc4random_uniform(UInt32(dnaSize-1))) - +func crossover(dna1: [UInt8], dna2: [UInt8], dnaSize: Int) -> [UInt8] { + let pos = Int.random(in: 0.. Date: Tue, 5 Mar 2019 22:38:53 -0500 Subject: [PATCH 192/271] Updates code to Swift 4.2 --- Genetic/gen.playground/Contents.swift | 192 +++++++++++--------------- 1 file changed, 84 insertions(+), 108 deletions(-) diff --git a/Genetic/gen.playground/Contents.swift b/Genetic/gen.playground/Contents.swift index 79a398ceb..d76342f56 100644 --- a/Genetic/gen.playground/Contents.swift +++ b/Genetic/gen.playground/Contents.swift @@ -1,14 +1,12 @@ -//: Playground - noun: a place where people can play -import Foundation extension String { - var unicodeArray: [UInt8] { - return [UInt8](self.utf8) - } + + var unicodeArray: [UInt8] { + return [UInt8](self.utf8) + } } - let lex: [UInt8] = " !\"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~".unicodeArray // This is the end goal and what we will be using to rate fitness. In the real world this will not exist @@ -17,132 +15,110 @@ let OPTIMAL:[UInt8] = "Hello, World".unicodeArray // The length of the string in our population. Organisms need to be similar let DNA_SIZE = OPTIMAL.count -// size of each generation +// Size of each generation let POP_SIZE = 50 -// max number of generations, script will stop when it reach 5000 if the optimal value is not found +// Max number of generations, script will stop when it reaches 5000 if the optimal value is not found let GENERATIONS = 5000 // The chance in which a random nucleotide can mutate (1/n) let MUTATION_CHANCE = 100 -func randomChar(from lexicon: [UInt8]) -> UInt8 { - let len = UInt32(lexicon.count-1) - let rand = Int(arc4random_uniform(len)) - return lexicon[rand] -} - func randomPopulation(from lexicon: [UInt8], populationSize: Int, dnaSize: Int) -> [[UInt8]] { - - var pop = [[UInt8]]() - - (0.. Int { - var fitness = 0 - (0...dna.count-1).forEach { c in - fitness += abs(Int(dna[c]) - Int(optimal[c])) - } - return fitness +func calculateFitness(dna: [UInt8], optimal: [UInt8]) -> Int { + var fitness = 0 + for index in dna.indices { + fitness += abs(Int(dna[index]) - Int(optimal[index])) + } + return fitness } -func weightedChoice(items:[(dna:[UInt8], weight:Double)]) -> (dna:[UInt8], weight:Double) { - - let total = items.reduce(0.0) { return $0 + $1.weight} - - var n = Double(arc4random_uniform(UInt32(total * 1000000.0))) / 1000000.0 - - for item in items { - if n < item.weight { - return item - } - n = n - item.weight +func weightedChoice(items: [(dna: [UInt8], weight: Double)]) -> (dna: [UInt8], weight: Double) { + + let total = items.reduce(0) { $0 + $1.weight } + var n = Double.random(in: 0..<(total * 1000000)) / 1000000.0 + + for item in items { + if n < item.weight { + return item } - return items[1] + n = n - item.weight + } + return items[1] } -func mutate(lexicon: [UInt8], dna:[UInt8], mutationChance:Int) -> [UInt8] { - var outputDna = dna - - (0.. [UInt8] { + var outputDna = dna + (0.. [UInt8] { - let pos = Int(arc4random_uniform(UInt32(dnaSize-1))) - - let dna1Index1 = dna1.index(dna1.startIndex, offsetBy: pos) - let dna2Index1 = dna2.index(dna2.startIndex, offsetBy: pos) - - return [UInt8](dna1.prefix(upTo: dna1Index1) + dna2.suffix(from: dna2Index1)) +func crossover(dna1: [UInt8], dna2: [UInt8], dnaSize: Int) -> [UInt8] { + let pos = Int.random(in: 0.. Date: Tue, 5 Mar 2019 22:46:10 -0500 Subject: [PATCH 193/271] Update README.markdown --- README.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.markdown b/README.markdown index 88ea35949..064a4616c 100644 --- a/README.markdown +++ b/README.markdown @@ -100,7 +100,7 @@ Bad sorting algorithms (don't use these!): - [Convex Hull](Convex%20Hull/). - [Miller-Rabin Primality Test](Miller-Rabin%20Primality%20Test/). Is the number a prime number? - [MinimumCoinChange](MinimumCoinChange/). A showcase for dynamic programming. - +- [Genetic](Genetic/). A simple example on how to slowly mutate a value to its ideal form, in the context of biological evolution. ### Mathematics - [Greatest Common Divisor (GCD)](GCD/). Special bonus: the least common multiple. From 04b2d3010b3db16b1bfd472e9686364bbf785a94 Mon Sep 17 00:00:00 2001 From: Kelvin Lau Date: Fri, 8 Mar 2019 23:13:13 -0500 Subject: [PATCH 194/271] Updates for Swift 5.0 Removes unnecessary equatable implementations, since default implementations of `Equatable` has identical result. --- .../Points Lines Planes/2D/Line2D.swift | 20 ------------------- 1 file changed, 20 deletions(-) diff --git a/Points Lines Planes/Points Lines Planes/2D/Line2D.swift b/Points Lines Planes/Points Lines Planes/2D/Line2D.swift index c92cbdbed..c23040b14 100644 --- a/Points Lines Planes/Points Lines Planes/2D/Line2D.swift +++ b/Points Lines Planes/Points Lines Planes/2D/Line2D.swift @@ -14,27 +14,11 @@ struct Line2D: Equatable { enum Slope: Equatable { case finite(slope: Double) case infinite(offset: Double) - - static func ==(lhs: Slope, rhs: Slope) -> Bool { - switch (lhs, rhs) { - case (.finite(let slope1), .finite(let slope2)): return slope1 == slope2 - case (.infinite(let offset1), .infinite(let offset2)): return offset1 == offset2 - default: return false - } - } } enum Direction: Equatable { case increasing case decreasing - - static func ==(lhs: Direction, rhs: Direction) -> Bool { - switch (lhs, rhs) { - case (.increasing, .increasing): return true - case (.decreasing, .decreasing): return true - default: return false - } - } } init(from p1: Point2D, to p2: Point2D) { @@ -154,8 +138,4 @@ struct Line2D: Equatable { return Line2D(slope: .finite(slope: 0), offset: p.y, direction: dir) } } - - static func ==(lhs: Line2D, rhs: Line2D) -> Bool { - return lhs.slope == rhs.slope && lhs.offset == rhs.offset && lhs.direction == rhs.direction - } } From 339cc1489b3b70e7464db4af7e8f398d45ce50db Mon Sep 17 00:00:00 2001 From: Kelvin Lau Date: Fri, 8 Mar 2019 23:13:42 -0500 Subject: [PATCH 195/271] Updates to Swift 5.0 Removes `Equatable` impl. --- Points Lines Planes/Points Lines Planes/2D/Point2D.swift | 4 ---- 1 file changed, 4 deletions(-) diff --git a/Points Lines Planes/Points Lines Planes/2D/Point2D.swift b/Points Lines Planes/Points Lines Planes/2D/Point2D.swift index f51ffd64d..bbd8305f8 100644 --- a/Points Lines Planes/Points Lines Planes/2D/Point2D.swift +++ b/Points Lines Planes/Points Lines Planes/2D/Point2D.swift @@ -9,10 +9,6 @@ struct Point2D: Equatable { var x: Double var y: Double - static func ==(lhs: Point2D, rhs: Point2D) -> Bool { - return lhs.x == rhs.x && lhs.y == rhs.y - } - // returns true if point is on or right of line func isRight(of line: Line2D) -> Bool { switch line.slope { From 5e55f9261bc4095df3424fdd9f238513e0eae8e5 Mon Sep 17 00:00:00 2001 From: Kelvin Lau Date: Sat, 9 Mar 2019 19:39:32 -0500 Subject: [PATCH 196/271] Adds Myers Difference Algorithm to Readme --- README.markdown | 1 + 1 file changed, 1 insertion(+) diff --git a/README.markdown b/README.markdown index 064a4616c..97917a320 100644 --- a/README.markdown +++ b/README.markdown @@ -101,6 +101,7 @@ Bad sorting algorithms (don't use these!): - [Miller-Rabin Primality Test](Miller-Rabin%20Primality%20Test/). Is the number a prime number? - [MinimumCoinChange](MinimumCoinChange/). A showcase for dynamic programming. - [Genetic](Genetic/). A simple example on how to slowly mutate a value to its ideal form, in the context of biological evolution. +- [Myers Difference Algorithm](Myers\ Difference\ Algorithm/). Finding the longest common subsequence of two sequences. ### Mathematics - [Greatest Common Divisor (GCD)](GCD/). Special bonus: the least common multiple. From 46c22ac590f580268a5c1fce288f6f8a720b37bb Mon Sep 17 00:00:00 2001 From: Kelvin Lau Date: Sat, 9 Mar 2019 19:40:06 -0500 Subject: [PATCH 197/271] Update README.markdown --- README.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.markdown b/README.markdown index 97917a320..c94716242 100644 --- a/README.markdown +++ b/README.markdown @@ -101,7 +101,7 @@ Bad sorting algorithms (don't use these!): - [Miller-Rabin Primality Test](Miller-Rabin%20Primality%20Test/). Is the number a prime number? - [MinimumCoinChange](MinimumCoinChange/). A showcase for dynamic programming. - [Genetic](Genetic/). A simple example on how to slowly mutate a value to its ideal form, in the context of biological evolution. -- [Myers Difference Algorithm](Myers\ Difference\ Algorithm/). Finding the longest common subsequence of two sequences. +- [Myers Difference Algorithm](Myers Difference Algorithm/). Finding the longest common subsequence of two sequences. ### Mathematics - [Greatest Common Divisor (GCD)](GCD/). Special bonus: the least common multiple. From 3849a1d6113ddb7d8ac24be2a1e9fc4b7677efd6 Mon Sep 17 00:00:00 2001 From: Kelvin Lau Date: Sat, 9 Mar 2019 19:41:21 -0500 Subject: [PATCH 198/271] Update README.markdown --- README.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.markdown b/README.markdown index c94716242..d66eee5d8 100644 --- a/README.markdown +++ b/README.markdown @@ -101,7 +101,7 @@ Bad sorting algorithms (don't use these!): - [Miller-Rabin Primality Test](Miller-Rabin%20Primality%20Test/). Is the number a prime number? - [MinimumCoinChange](MinimumCoinChange/). A showcase for dynamic programming. - [Genetic](Genetic/). A simple example on how to slowly mutate a value to its ideal form, in the context of biological evolution. -- [Myers Difference Algorithm](Myers Difference Algorithm/). Finding the longest common subsequence of two sequences. +- [Myers Difference Algorithm](Myers%20Difference%20Algorithm/). Finding the longest common subsequence of two sequences. ### Mathematics - [Greatest Common Divisor (GCD)](GCD/). Special bonus: the least common multiple. From 0d5e1b94e49311607fc0b30cc379304fe2123798 Mon Sep 17 00:00:00 2001 From: Kelvin Lau Date: Thu, 14 Mar 2019 22:44:36 -0400 Subject: [PATCH 199/271] Update README.markdown Adds a reference to the GitHub page via #720 --- README.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.markdown b/README.markdown index d66eee5d8..44879e8f8 100644 --- a/README.markdown +++ b/README.markdown @@ -8,7 +8,7 @@ If you're a computer science student who needs to learn this stuff for exams -- The goal of this project is to **explain how algorithms work**. The focus is on clarity and readability of the code, not on making a reusable library that you can drop into your own projects. That said, most of the code should be ready for production use but you may need to tweak it to fit into your own codebase. -Code is compatible with **Xcode 10** and **Swift 4.2**. We'll keep this updated with the latest version of Swift. +Code is compatible with **Xcode 10** and **Swift 4.2**. We'll keep this updated with the latest version of Swift. If you're interested in a GitHub pages version of the repo, check out [this](https://aquarchitect.github.io/swift-algorithm-club/). :heart_eyes: **Suggestions and contributions are welcome!** :heart_eyes: From 56e2fc9047a4523d62d3f1fe4eac679b20382509 Mon Sep 17 00:00:00 2001 From: bbvch13531 Date: Fri, 15 Mar 2019 19:52:09 +0900 Subject: [PATCH 200/271] Change return type to brief type. Fixes :#865 Signed-off-by: bbvch13531 --- .../Sources/BinarySearchTree.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Binary Search Tree/Solution 1/BinarySearchTree.playground/Sources/BinarySearchTree.swift b/Binary Search Tree/Solution 1/BinarySearchTree.playground/Sources/BinarySearchTree.swift index 34ade3896..2d0eb7e57 100644 --- a/Binary Search Tree/Solution 1/BinarySearchTree.playground/Sources/BinarySearchTree.swift +++ b/Binary Search Tree/Solution 1/BinarySearchTree.playground/Sources/BinarySearchTree.swift @@ -235,7 +235,7 @@ extension BinarySearchTree { /* Finds the node whose value precedes our value in sorted order. */ - public func predecessor() -> BinarySearchTree? { + public func predecessor() -> BinarySearchTree? { if let left = left { return left.maximum() } else { @@ -251,7 +251,7 @@ extension BinarySearchTree { /* Finds the node whose value succeeds our value in sorted order. */ - public func successor() -> BinarySearchTree? { + public func successor() -> BinarySearchTree? { if let right = right { return right.minimum() } else { From 7065c1a2d0aa0633188cdb27de69c11ab8d740d5 Mon Sep 17 00:00:00 2001 From: Dmitry Cherednikov Date: Sat, 16 Mar 2019 15:44:00 +0400 Subject: [PATCH 201/271] Implement getPredecessor(). --- Red-Black Tree/README.markdown | 1 + .../Sources/RedBlackTree.swift | 27 ++++++++++++++++++- 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/Red-Black Tree/README.markdown b/Red-Black Tree/README.markdown index fd6c4db18..352588056 100644 --- a/Red-Black Tree/README.markdown +++ b/Red-Black Tree/README.markdown @@ -29,6 +29,7 @@ From [CLRS] ## Methods Nodes: +* `nodeX.getPredecessor()` Returns the inorder predecessor of nodeX * `nodeX.getSuccessor()` Returns the inorder successor of nodeX * `nodeX.minimum()` Returns the node with the minimum key of the subtree of nodeX * `nodeX.maximum()` Returns the node with the maximum key of the subtree of nodeX diff --git a/Red-Black Tree/RedBlackTree.playground/Sources/RedBlackTree.swift b/Red-Black Tree/RedBlackTree.playground/Sources/RedBlackTree.swift index 59633031d..b88cd7cf5 100644 --- a/Red-Black Tree/RedBlackTree.playground/Sources/RedBlackTree.swift +++ b/Red-Black Tree/RedBlackTree.playground/Sources/RedBlackTree.swift @@ -60,6 +60,10 @@ public class RBTreeNode: Equatable { self.init(key: nil, leftChild: nil, rightChild: nil, parent: nil) self.color = .black } + + public func getKey() -> T? { + return key + } var isRoot: Bool { return parent == nil @@ -120,9 +124,30 @@ extension RBTreeNode { } } -// MARK: - Finding a nodes successor +// MARK: - Finding a nodes successor and predecessor extension RBTreeNode { + /* + * Returns the inorder predecessor node of a node + * The predecessor is a node with the next smaller key value of the current node + */ + public func getPredecessor() -> RBNode? { + // if node has left child: predecessor is min of this left tree + if let leftChild = leftChild, !leftChild.isNullLeaf { + return leftChild.maximum() + } + // else go upward while node is left child + var currentNode = self + var parent = currentNode.parent + while currentNode.isLeftChild { + if let parent = parent { + currentNode = parent + } + parent = currentNode.parent + } + return parent + } + /* * Returns the inorder successor node of a node * The successor is a node with the next larger key value of the current node From 6e8b5cdc37324a4120abee841d89cef36ab6352f Mon Sep 17 00:00:00 2001 From: TL Date: Wed, 20 Mar 2019 16:09:34 +0800 Subject: [PATCH 202/271] Update Shuffle MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit according to https://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle `checks if j ≠ i may be omitted`, and also remove checking logic will optimise performance(tested by 100000 times random). --- Shuffle/README.markdown | 3 --- Shuffle/Shuffle.swift | 3 --- 2 files changed, 6 deletions(-) diff --git a/Shuffle/README.markdown b/Shuffle/README.markdown index 63868767b..d8ab7ff78 100644 --- a/Shuffle/README.markdown +++ b/Shuffle/README.markdown @@ -96,9 +96,6 @@ public func shuffledArray(_ n: Int) -> [Int] { var a = [Int](repeating: 0, count: n) for i in 0.. [Int] { var a = Array(repeating: 0, count: n) for i in 0.. Date: Thu, 21 Mar 2019 10:17:06 -0400 Subject: [PATCH 203/271] Update SlowSort.swift --- Slow Sort/SlowSort.swift | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/Slow Sort/SlowSort.swift b/Slow Sort/SlowSort.swift index bd8288b18..546a36395 100644 --- a/Slow Sort/SlowSort.swift +++ b/Slow Sort/SlowSort.swift @@ -7,14 +7,14 @@ // func slowSort(_ i: Int, _ j: Int, _ numberList: inout [Int]) { - guard if i < j else { return } - let m = (i+j)/2 - slowSort(i, m, &numberList) - slowSort(m+1, j, &numberList) - if numberList[j] < numberList[m] { - let temp = numberList[j] - numberList[j] = numberList[m] - numberList[m] = temp - } - slowSort(i, j-1, &numberList) + guard if i < j else { return } + let m = (i+j)/2 + slowSort(i, m, &numberList) + slowSort(m+1, j, &numberList) + if numberList[j] < numberList[m] { + let temp = numberList[j] + numberList[j] = numberList[m] + numberList[m] = temp + } + slowSort(i, j-1, &numberList) } From 7457ceb7e9ec688ac11db158ac3d32118df49b0f Mon Sep 17 00:00:00 2001 From: Kelvin Lau Date: Thu, 21 Mar 2019 10:25:04 -0400 Subject: [PATCH 204/271] Two-spaced indents --- Comb Sort/Tests/CombSortTests.swift | 32 ++++++++++++----------------- 1 file changed, 13 insertions(+), 19 deletions(-) diff --git a/Comb Sort/Tests/CombSortTests.swift b/Comb Sort/Tests/CombSortTests.swift index 166065484..1d83af002 100644 --- a/Comb Sort/Tests/CombSortTests.swift +++ b/Comb Sort/Tests/CombSortTests.swift @@ -9,26 +9,20 @@ import XCTest class CombSortTests: XCTestCase { - var sequence: [Int]! - let expectedSequence: [Int] = [-12, -10, -1, 2, 9, 32, 55, 67, 89, 101] - - func testSwiftVersion(){ - #if swift(>=4.2) - print("Hello, Swift 4.2!") - #endif - } + var sequence: [Int]! + let expectedSequence: [Int] = [-12, -10, -1, 2, 9, 32, 55, 67, 89, 101] - override func setUp() { - super.setUp() - sequence = [2, 32, 9, -1, 89, 101, 55, -10, -12, 67] - } + override func setUp() { + super.setUp() + sequence = [2, 32, 9, -1, 89, 101, 55, -10, -12, 67] + } - override func tearDown() { - super.tearDown() - } + override func tearDown() { + super.tearDown() + } - func testCombSort() { - let sortedSequence = combSort(sequence) - XCTAssertEqual(sortedSequence, expectedSequence) - } + func testCombSort() { + let sortedSequence = combSort(sequence) + XCTAssertEqual(sortedSequence, expectedSequence) + } } From fdab1a2d7a9f9797ed7be27c5023f284c47f38ea Mon Sep 17 00:00:00 2001 From: Kelvin Lau Date: Thu, 21 Mar 2019 10:25:24 -0400 Subject: [PATCH 205/271] two spaced indents --- Slow Sort/SlowSort.swift | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Slow Sort/SlowSort.swift b/Slow Sort/SlowSort.swift index 546a36395..968f6841b 100644 --- a/Slow Sort/SlowSort.swift +++ b/Slow Sort/SlowSort.swift @@ -12,9 +12,9 @@ func slowSort(_ i: Int, _ j: Int, _ numberList: inout [Int]) { slowSort(i, m, &numberList) slowSort(m+1, j, &numberList) if numberList[j] < numberList[m] { - let temp = numberList[j] - numberList[j] = numberList[m] - numberList[m] = temp + let temp = numberList[j] + numberList[j] = numberList[m] + numberList[m] = temp } slowSort(i, j-1, &numberList) } From 7405c64e2cf7c035dce15207bba0fe7434010b55 Mon Sep 17 00:00:00 2001 From: Priyanka- Date: Sun, 24 Mar 2019 12:20:31 -0700 Subject: [PATCH 206/271] Kth Largest Element: updated to use Int.random API which has been introduced with Swift 4.2 --- .../kthLargest.playground/Sources/kthLargest.swift | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/Kth Largest Element/kthLargest.playground/Sources/kthLargest.swift b/Kth Largest Element/kthLargest.playground/Sources/kthLargest.swift index 397c43a38..aad15eac6 100644 --- a/Kth Largest Element/kthLargest.playground/Sources/kthLargest.swift +++ b/Kth Largest Element/kthLargest.playground/Sources/kthLargest.swift @@ -16,12 +16,6 @@ public func kthLargest(_ a: [Int], _ k: Int) -> Int? { // MARK: - Randomized selection -/* Returns a random integer in the range min...max, inclusive. */ -public func random(min: Int, max: Int) -> Int { - assert(min < max) - return min + Int(arc4random_uniform(UInt32(max - min + 1))) -} - /* Returns the i-th smallest element from the array. @@ -39,7 +33,7 @@ public func randomizedSelect(_ array: [T], order k: Int) -> T { var a = array func randomPivot(_ a: inout [T], _ low: Int, _ high: Int) -> T { - let pivotIndex = random(min: low, max: high) + let pivotIndex = Int.random(in: low...high) a.swapAt(pivotIndex, high) return a[high] } From b6e9a40652d489605772f284ad2dac4a033fd216 Mon Sep 17 00:00:00 2001 From: TL Date: Tue, 26 Mar 2019 15:34:12 +0800 Subject: [PATCH 207/271] Update Shuffle --- Shuffle/README.markdown | 4 ++++ Shuffle/Shuffle.swift | 1 + 2 files changed, 5 insertions(+) diff --git a/Shuffle/README.markdown b/Shuffle/README.markdown index d8ab7ff78..5a2a07a98 100644 --- a/Shuffle/README.markdown +++ b/Shuffle/README.markdown @@ -96,6 +96,8 @@ public func shuffledArray(_ n: Int) -> [Int] { var a = [Int](repeating: 0, count: n) for i in 0.. [Int] { var a = Array(repeating: 0, count: n) for i in 0.. Date: Sun, 28 Apr 2019 13:19:59 -0400 Subject: [PATCH 208/271] Adds Closest Pair --- README.markdown | 1 + 1 file changed, 1 insertion(+) diff --git a/README.markdown b/README.markdown index 44879e8f8..3e0174576 100644 --- a/README.markdown +++ b/README.markdown @@ -208,6 +208,7 @@ A lot of software developer interview questions consist of algorithmic puzzles. - [Dining Philosophers](DiningPhilosophers/) - [Egg Drop Problem](Egg%20Drop%20Problem/) - [Encoding and Decoding Binary Tree](Encode%20and%20Decode%20Tree/) +- [Closest Pair](Closest%20Pair/) ## Learn more! From 721af5d569661effa976e88fc65a14fd3961b826 Mon Sep 17 00:00:00 2001 From: Vladislav Badulin Date: Mon, 29 Apr 2019 21:24:24 +0200 Subject: [PATCH 209/271] This fixes the unlikely event that the generated hashValue happens to be the equal to Int.min, in which case the abs value of it would be Int.max + 1 causing overflow. --- Hash Table/HashTable.playground/Sources/HashTable.swift | 2 +- Hash Table/README.markdown | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Hash Table/HashTable.playground/Sources/HashTable.swift b/Hash Table/HashTable.playground/Sources/HashTable.swift index 476a51174..f2a1be040 100644 --- a/Hash Table/HashTable.playground/Sources/HashTable.swift +++ b/Hash Table/HashTable.playground/Sources/HashTable.swift @@ -131,7 +131,7 @@ public struct HashTable { Returns the given key's array index. */ private func index(forKey key: Key) -> Int { - return abs(key.hashValue) % buckets.count + return abs(key.hashValue % buckets.count) } } diff --git a/Hash Table/README.markdown b/Hash Table/README.markdown index 9c4065a51..fb0bda788 100644 --- a/Hash Table/README.markdown +++ b/Hash Table/README.markdown @@ -141,7 +141,7 @@ The hash table does not do anything yet, so let's add the remaining functionalit ```swift private func index(forKey key: Key) -> Int { - return abs(key.hashValue) % buckets.count + return abs(key.hashValue % buckets.count) } ``` From 15db2b6d953d1130acb711a358a79f5237979d02 Mon Sep 17 00:00:00 2001 From: Vanderlei Alves <39912609+vzanshin@users.noreply.github.com> Date: Fri, 3 May 2019 15:47:53 -0300 Subject: [PATCH 210/271] Fix typo and grammar --- .github/CONTRIBUTING.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index e5d00c17b..29f4ca7e1 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -6,7 +6,7 @@ Want to help out with the Swift Algorithm Club? Great! While we don't have stric Our repo is all about learning. The `README` file is the cake, and the sample code is the cherry on top. A good contribution has succinct explanations supported by diagrams. Code is best introduced in chunks, weaved into the explanations where relevant. -> When choosing between brievity and performance, err to the side of brievity as long as the time complexity of the particular implementation is the same. You can make a note afterwards suggesting a more performant way of doing things. +> When choosing between brevity and performance, err to the side of brevity as long as the time complexity of the particular implementation is the same. You can make a note afterwards suggesting a more performant way of doing things. **API Design Guidelines** @@ -22,7 +22,7 @@ We follow the following Swift [style guide](https://github.com/raywenderlich/swi Unit tests. Fixes for typos. No contribution is too small. :-) -The repository has over 100 different data structures and algorithms. We're always interested in improvements to existing implementations and better explanations. Suggestions for making the code more Swift-like or to make it fit better with the standard library is most welcomed. +The repository has over 100 different data structures and algorithms. We're always interested in improvements to existing implementations and better explanations. Suggestions for making the code more Swift-like or to make it fit better with the standard library are most welcome. ### New Contributions From 3f1d661b2d95eb0349d824277447c63c0aa3ecf1 Mon Sep 17 00:00:00 2001 From: Vanderlei Alves <39912609+vzanshin@users.noreply.github.com> Date: Wed, 8 May 2019 16:39:15 -0300 Subject: [PATCH 211/271] Fix minor typo at Heap/README --- Heap/README.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Heap/README.markdown b/Heap/README.markdown index 76d2bee39..6c65fe9c8 100755 --- a/Heap/README.markdown +++ b/Heap/README.markdown @@ -29,7 +29,7 @@ As a result of this heap property, a max-heap always stores its largest item at ## How does a heap compare to regular trees? -A heap is not a replacement for a binary search tree, and there are similarities and differnces between them. Here are some main differences: +A heap is not a replacement for a binary search tree, and there are similarities and differences between them. Here are some main differences: **Order of the nodes.** In a [binary search tree (BST)](../Binary%20Search%20Tree/), the left child must be smaller than its parent, and the right child must be greater. This is not true for a heap. In a max-heap both children must be smaller than the parent, while in a min-heap they both must be greater. From 78a7ceeff6c59a740428c6fae41a79f660c5a58c Mon Sep 17 00:00:00 2001 From: Kenny Schlagel Date: Sun, 7 Jul 2019 19:52:11 -0600 Subject: [PATCH 212/271] Improvements to Count Occurrences --- .../Contents.swift | 20 +++++++-------- Count Occurrences/CountOccurrences.swift | 25 ++++++++++--------- Count Occurrences/README.markdown | 12 ++++----- 3 files changed, 29 insertions(+), 28 deletions(-) diff --git a/Count Occurrences/CountOccurrences.playground/Contents.swift b/Count Occurrences/CountOccurrences.playground/Contents.swift index a34e3485f..6ab4c00f3 100644 --- a/Count Occurrences/CountOccurrences.playground/Contents.swift +++ b/Count Occurrences/CountOccurrences.playground/Contents.swift @@ -1,11 +1,11 @@ -func countOccurrencesOfKey(_ key: Int, inArray a: [Int]) -> Int { - func leftBoundary() -> Int { +func countOccurrences(of key: T, in array: [T]) -> Int { + var leftBoundary: Int { var low = 0 - var high = a.count + var high = array.count while low < high { let midIndex = low + (high - low)/2 - if a[midIndex] < key { + if array[midIndex] < key { low = midIndex + 1 } else { high = midIndex @@ -14,12 +14,12 @@ func countOccurrencesOfKey(_ key: Int, inArray a: [Int]) -> Int { return low } - func rightBoundary() -> Int { + var rightBoundary: Int { var low = 0 - var high = a.count + var high = array.count while low < high { let midIndex = low + (high - low)/2 - if a[midIndex] > key { + if array[midIndex] > key { high = midIndex } else { low = midIndex + 1 @@ -28,13 +28,13 @@ func countOccurrencesOfKey(_ key: Int, inArray a: [Int]) -> Int { return low } - return rightBoundary() - leftBoundary() + return rightBoundary - leftBoundary } // Simple test let a = [ 0, 1, 1, 3, 3, 3, 3, 6, 8, 10, 11, 11 ] -countOccurrencesOfKey(3, inArray: a) +countOccurrences(of: 3, in: a) // Test with arrays of random size and contents (see debug output) @@ -59,6 +59,6 @@ for _ in 0..<10 { // Note: we also test -1 and 6 to check the edge cases. for k in -1...6 { - print("\t\(k): \(countOccurrencesOfKey(k, inArray: a))") + print("\t\(k): \(countOccurrences(of: k, in: a))") } } diff --git a/Count Occurrences/CountOccurrences.swift b/Count Occurrences/CountOccurrences.swift index 10dd12c4f..532e3810e 100644 --- a/Count Occurrences/CountOccurrences.swift +++ b/Count Occurrences/CountOccurrences.swift @@ -1,14 +1,15 @@ -/* - Counts the number of times a value appears in an array in O(lg n) time. - The array must be sorted from low to high. -*/ -func countOccurrencesOfKey(_ key: Int, inArray a: [Int]) -> Int { - func leftBoundary() -> Int { +/// Counts the number of times a value appears in an array in O(log n) time. The array must be sorted from low to high. +/// +/// - Parameter key: the key to be searched for in the array +/// - Parameter array: the array to search +/// - Returns: the count of occurences of the key in the given array +func countOccurrences(of key: T, in array: [T]) -> Int { + var leftBoundary: Int { var low = 0 - var high = a.count + var high = array.count while low < high { let midIndex = low + (high - low)/2 - if a[midIndex] < key { + if array[midIndex] < key { low = midIndex + 1 } else { high = midIndex @@ -17,12 +18,12 @@ func countOccurrencesOfKey(_ key: Int, inArray a: [Int]) -> Int { return low } - func rightBoundary() -> Int { + var rightBoundary: Int { var low = 0 - var high = a.count + var high = array.count while low < high { let midIndex = low + (high - low)/2 - if a[midIndex] > key { + if array[midIndex] > key { high = midIndex } else { low = midIndex + 1 @@ -31,5 +32,5 @@ func countOccurrencesOfKey(_ key: Int, inArray a: [Int]) -> Int { return low } - return rightBoundary() - leftBoundary() + return rightBoundary - leftBoundary } diff --git a/Count Occurrences/README.markdown b/Count Occurrences/README.markdown index 85b77d2d0..297bc4b0f 100644 --- a/Count Occurrences/README.markdown +++ b/Count Occurrences/README.markdown @@ -22,8 +22,8 @@ The trick is to use two binary searches, one to find where the `3`s start (the l In code this looks as follows: ```swift -func countOccurrencesOfKey(_ key: Int, inArray a: [Int]) -> Int { - func leftBoundary() -> Int { +func countOccurrences(of key: T, in array: [T]) -> Int { + var leftBoundary: Int { var low = 0 var high = a.count while low < high { @@ -37,7 +37,7 @@ func countOccurrencesOfKey(_ key: Int, inArray a: [Int]) -> Int { return low } - func rightBoundary() -> Int { + var rightBoundary: Int { var low = 0 var high = a.count while low < high { @@ -51,11 +51,11 @@ func countOccurrencesOfKey(_ key: Int, inArray a: [Int]) -> Int { return low } - return rightBoundary() - leftBoundary() + return rightBoundary - leftBoundary } ``` -Notice that the helper functions `leftBoundary()` and `rightBoundary()` are very similar to the [binary search](../Binary%20Search/) algorithm. The big difference is that they don't stop when they find the search key, but keep going. +Notice that the variables `leftBoundary` and `rightBoundary` are very similar to the [binary search](../Binary%20Search/) algorithm. The big difference is that they don't stop when they find the search key, but keep going. Also, notice that we constrain the type `T` to be Comparable so that the algorithm can be applied to an array of Strings, Ints or other types that conform to the Swift Comparable protocol. To test this algorithm, copy the code to a playground and then do: @@ -113,7 +113,7 @@ The right boundary is at index 7. The difference between the two boundaries is 7 Each binary search took 4 steps, so in total this algorithm took 8 steps. Not a big gain on an array of only 12 items, but the bigger the array, the more efficient this algorithm becomes. For a sorted array with 1,000,000 items, it only takes 2 x 20 = 40 steps to count the number of occurrences for any particular value. -By the way, if the value you're looking for is not in the array, then `rightBoundary()` and `leftBoundary()` return the same value and so the difference between them is 0. +By the way, if the value you're looking for is not in the array, then `rightBoundary` and `leftBoundary` return the same value and so the difference between them is 0. This is an example of how you can modify the basic binary search to solve other algorithmic problems as well. Of course, it does require that the array is sorted. From 6e64f07b43971ba04b85887bf3bf2d616243c21a Mon Sep 17 00:00:00 2001 From: ygit Date: Wed, 10 Jul 2019 02:38:29 +0530 Subject: [PATCH 213/271] added Big O computation comparison graph --- Big-O Notation.markdown | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Big-O Notation.markdown b/Big-O Notation.markdown index 257f80462..9509331a5 100644 --- a/Big-O Notation.markdown +++ b/Big-O Notation.markdown @@ -18,6 +18,11 @@ Big-O | Name | Description **O(n!)** | factorial | **Intolerably slow.** It literally takes a million years to do anything. + +![Comparison of Big O computations](https://upload.wikimedia.org/wikipedia/commons/7/7e/Comparison_computational_complexity.svg) + + + Below are some examples for each category of performance: **O(1)** From 762de527ad71e07f36ca9fd417819d733d298bdd Mon Sep 17 00:00:00 2001 From: markgz Date: Thu, 8 Aug 2019 17:09:28 +0800 Subject: [PATCH 214/271] The code of O(2^n) isn't correct which is O(n) Need solve two smaller problems in one recursive call --- Big-O Notation.markdown | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Big-O Notation.markdown b/Big-O Notation.markdown index 9509331a5..c3f020df2 100644 --- a/Big-O Notation.markdown +++ b/Big-O Notation.markdown @@ -124,9 +124,8 @@ Below are some examples for each category of performance: func solveHanoi(n: Int, from: String, to: String, spare: String) { guard n >= 1 else { return } if n > 1 { - solveHanoi(n: n - 1, from: from, to: spare, spare: to) - } else { - solveHanoi(n: n - 1, from: spare, to: to, spare: from) + solveHanoi(n: n - 1, from: from, to: spare, spare: to) + solveHanoi(n: n - 1, from: spare, to: to, spare: from) } } ``` From eb9424d3f69d18a311c474907c2775f2a07d2852 Mon Sep 17 00:00:00 2001 From: abuzeid ibrahim Date: Thu, 15 Aug 2019 14:21:38 +0200 Subject: [PATCH 215/271] rename variables with convenience names --- Insertion Sort/InsertionSort.swift | 42 +++++++++++++++--------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/Insertion Sort/InsertionSort.swift b/Insertion Sort/InsertionSort.swift index 2ad607ac8..926dad302 100644 --- a/Insertion Sort/InsertionSort.swift +++ b/Insertion Sort/InsertionSort.swift @@ -2,22 +2,22 @@ /// /// - Parameters: /// - array: the array of elements to be sorted +/// - sortedArray: copy the array to save stability /// - isOrderedBefore: returns true if the elements provided are in the corect order /// - Returns: a sorted array containing the same elements func insertionSort(_ array: [T], _ isOrderedBefore: (T, T) -> Bool) -> [T] { - guard array.count > 1 else { return array } - - var a = array - for x in 1.. 0 && isOrderedBefore(temp, a[y - 1]) { - a[y] = a[y - 1] - y -= 1 + guard array.count > 1 else { return array } + var sortedArray = array + for index in 1.. 0, isOrderedBefore(temp, sortedArray[currentIndex - 1]) { + sortedArray[currentIndex] = sortedArray[currentIndex - 1] + currentIndex -= 1 + } + sortedArray[currentIndex] = temp } - a[y] = temp - } - return a + return sortedArray } /// Performs the Insertion sort algorithm to a given array @@ -27,15 +27,15 @@ func insertionSort(_ array: [T], _ isOrderedBefore: (T, T) -> Bool) -> [T] { func insertionSort(_ array: [T]) -> [T] { guard array.count > 1 else { return array } - var a = array - for x in 1.. 0 && temp < a[y - 1] { - a[y] = a[y - 1] - y -= 1 + var sortedArray = array + for index in 1.. 0, temp < sortedArray[currentIndex - 1] { + sortedArray[currentIndex] = sortedArray[currentIndex - 1] + currentIndex -= 1 } - a[y] = temp + sortedArray[currentIndex] = temp } - return a + return sortedArray } From 92e797ac998b3f7a00cb1c2247c01d927cfa5414 Mon Sep 17 00:00:00 2001 From: abuzeid ibrahim Date: Thu, 15 Aug 2019 14:31:22 +0200 Subject: [PATCH 216/271] rename variables in the playground --- .../InsertionSort.playground/Contents.swift | 36 +++++++++---------- .../contents.xcplayground | 2 +- 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/Insertion Sort/InsertionSort.playground/Contents.swift b/Insertion Sort/InsertionSort.playground/Contents.swift index 184fc36e4..e1d3a312e 100644 --- a/Insertion Sort/InsertionSort.playground/Contents.swift +++ b/Insertion Sort/InsertionSort.playground/Contents.swift @@ -9,17 +9,17 @@ func insertionSort(_ array: [T], _ isOrderedBefore: (T, T) -> Bool) -> [T] { guard array.count > 1 else { return array } - var a = array - for x in 1.. 0 && isOrderedBefore(temp, a[y - 1]) { - a[y] = a[y - 1] - y -= 1 + var sortedArray = array + for index in 1.. 0 && isOrderedBefore(temp, sortedArray[currentIndex - 1]) { + sortedArray[currentIndex] = sortedArray[currentIndex - 1] + currentIndex -= 1 } - a[y] = temp + sortedArray[currentIndex] = temp } - return a + return sortedArray } /// Performs the Insertion sort algorithm to a given array @@ -27,17 +27,17 @@ func insertionSort(_ array: [T], _ isOrderedBefore: (T, T) -> Bool) -> [T] { /// - Parameter array: the array to be sorted, conatining elements that conform to the Comparable protocol /// - Returns: a sorted array containing the same elements func insertionSort(_ array: [T]) -> [T] { - var a = array - for x in 1.. 0 && temp < a[y - 1] { - a[y] = a[y - 1] - y -= 1 + var sortedArray = array + for index in 1.. 0 && temp < sortedArray[currentIndex - 1] { + sortedArray[currentIndex] = sortedArray[currentIndex - 1] + currentIndex -= 1 } - a[y] = temp + sortedArray[currentIndex] = temp } - return a + return sortedArray } let list = [ 10, -1, 3, 9, 2, 27, 8, 5, 1, 3, 0, 26 ] diff --git a/Insertion Sort/InsertionSort.playground/contents.xcplayground b/Insertion Sort/InsertionSort.playground/contents.xcplayground index 9f9eecc96..06828af92 100644 --- a/Insertion Sort/InsertionSort.playground/contents.xcplayground +++ b/Insertion Sort/InsertionSort.playground/contents.xcplayground @@ -1,4 +1,4 @@ - + \ No newline at end of file From 6dc91c4a7bee34ff2b4fe9f4f2d5d77d3d42e55c Mon Sep 17 00:00:00 2001 From: Abuzeid-Ibrahim Date: Thu, 15 Aug 2019 14:35:33 +0200 Subject: [PATCH 217/271] Update README.markdown --- Insertion Sort/README.markdown | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/Insertion Sort/README.markdown b/Insertion Sort/README.markdown index 4bad29aa1..8c2a5c1a0 100644 --- a/Insertion Sort/README.markdown +++ b/Insertion Sort/README.markdown @@ -91,15 +91,15 @@ Here is an implementation of insertion sort in Swift: ```swift func insertionSort(_ array: [Int]) -> [Int] { - var a = array // 1 - for x in 1.. 0 && a[y] < a[y - 1] { // 3 - a.swapAt(y - 1, y) - y -= 1 + var sortedArray = array // 1 + for index in 1.. 0 && sortedArray[currentIndex] < sortedArray[currentIndex - 1] { // 3 + sortedArray.swapAt(currentIndex - 1, currentIndex) + currentIndex -= 1 } } - return a + return sortedArray } @@ -154,17 +154,17 @@ In code that looks like this: ```swift func insertionSort(_ array: [Int]) -> [Int] { - var a = array - for x in 1.. 0 && temp < a[y - 1] { - a[y] = a[y - 1] // 1 - y -= 1 + var sortedArray = array + for index in 1.. 0 && temp < sortedArray[currentIndex - 1] { + sortedArray[currentIndex] = sortedArray[currentIndex - 1] // 1 + currentIndex -= 1 } - a[y] = temp // 2 + sortedArray[currentIndex] = temp // 2 } - return a + return sortedArray } ``` From dfea1d68dd6151f88221c6be34a0a78002c50537 Mon Sep 17 00:00:00 2001 From: Pavel Date: Sat, 31 Aug 2019 11:12:51 +0500 Subject: [PATCH 218/271] Update Queue-Optimized.swift --- Queue/Queue-Optimized.swift | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/Queue/Queue-Optimized.swift b/Queue/Queue-Optimized.swift index 7dff91698..aedf9c67f 100644 --- a/Queue/Queue-Optimized.swift +++ b/Queue/Queue-Optimized.swift @@ -23,7 +23,7 @@ public struct Queue { } public mutating func dequeue() -> T? { - guard head < array.count, let element = array[head] else { return nil } + guard let element = array[guarded: head] else { return nil } array[head] = nil head += 1 @@ -45,3 +45,14 @@ public struct Queue { } } } + +extension Array { + + subscript(guarded idx: Int) -> Element? { + guard (startIndex.. Date: Tue, 3 Sep 2019 16:14:28 +0200 Subject: [PATCH 219/271] move documentation to func body --- Insertion Sort/InsertionSort.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Insertion Sort/InsertionSort.swift b/Insertion Sort/InsertionSort.swift index 926dad302..e24ede905 100644 --- a/Insertion Sort/InsertionSort.swift +++ b/Insertion Sort/InsertionSort.swift @@ -2,11 +2,11 @@ /// /// - Parameters: /// - array: the array of elements to be sorted -/// - sortedArray: copy the array to save stability /// - isOrderedBefore: returns true if the elements provided are in the corect order /// - Returns: a sorted array containing the same elements func insertionSort(_ array: [T], _ isOrderedBefore: (T, T) -> Bool) -> [T] { guard array.count > 1 else { return array } + /// - sortedArray: copy the array to save stability var sortedArray = array for index in 1.. Date: Fri, 6 Sep 2019 11:39:57 +0500 Subject: [PATCH 220/271] Added changed by opened discussions --- Queue/Queue-Optimized.swift | 2 -- 1 file changed, 2 deletions(-) diff --git a/Queue/Queue-Optimized.swift b/Queue/Queue-Optimized.swift index aedf9c67f..3b17b98cb 100644 --- a/Queue/Queue-Optimized.swift +++ b/Queue/Queue-Optimized.swift @@ -47,12 +47,10 @@ public struct Queue { } extension Array { - subscript(guarded idx: Int) -> Element? { guard (startIndex.. Date: Fri, 6 Sep 2019 13:18:40 -0700 Subject: [PATCH 221/271] Updated broken link Updated link to Boyer-Moore-Horspool algorithm. --- Knuth-Morris-Pratt/README.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Knuth-Morris-Pratt/README.markdown b/Knuth-Morris-Pratt/README.markdown index 95fdea9e9..2e4d5360b 100644 --- a/Knuth-Morris-Pratt/README.markdown +++ b/Knuth-Morris-Pratt/README.markdown @@ -14,7 +14,7 @@ let concert = "🎼🎹🎹🎸🎸🎻🎻🎷🎺🎤👏👏👏" concert.indexesOf(ptnr: "🎻🎷") // Output: [6] ``` -The [Knuth-Morris-Pratt algorithm](https://en.wikipedia.org/wiki/Knuth–Morris–Pratt_algorithm) is considered one of the best algorithms for solving the pattern matching problem. Although in practice [Boyer-Moore](../Boyer-Moore/) is usually preferred, the algorithm that we will introduce is simpler, and has the same (linear) running time. +The [Knuth-Morris-Pratt algorithm](https://en.wikipedia.org/wiki/Knuth–Morris–Pratt_algorithm) is considered one of the best algorithms for solving the pattern matching problem. Although in practice [Boyer-Moore](../Boyer-Moore-Horspool/) is usually preferred, the algorithm that we will introduce is simpler, and has the same (linear) running time. The idea behind the algorithm is not too different from the [naive string search](../Brute-Force%20String%20Search/) procedure. As it, Knuth-Morris-Pratt aligns the text with the pattern and goes with character comparisons from left to right. But, instead of making a shift of one character when a mismatch occurs, it uses a more intelligent way to move the pattern along the text. In fact, the algorithm features a pattern pre-processing stage where it acquires all the informations that will make the algorithm skip redundant comparisons, resulting in larger shifts. From da2085fc5bd7b08aec0b061301218e90fdf3d35e Mon Sep 17 00:00:00 2001 From: Joe Soultanis Date: Tue, 29 Oct 2019 16:55:50 -0700 Subject: [PATCH 222/271] updaing incorrect big-O performance documentation of heap removal --- Heap/Heap.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Heap/Heap.swift b/Heap/Heap.swift index cf39fb8a5..7560bc7b9 100755 --- a/Heap/Heap.swift +++ b/Heap/Heap.swift @@ -212,7 +212,7 @@ extension Heap where T: Equatable { return nodes.index(where: { $0 == node }) } - /** Removes the first occurrence of a node from the heap. Performance: O(n log n). */ + /** Removes the first occurrence of a node from the heap. Performance: O(n). */ @discardableResult public mutating func remove(node: T) -> T? { if let index = index(of: node) { return remove(at: index) From 519a57ae2946033608bda0fe24d428e189212df4 Mon Sep 17 00:00:00 2001 From: Kelvin Lau Date: Tue, 29 Oct 2019 22:35:24 -0400 Subject: [PATCH 223/271] Removes the workspace. --- .../contents.xcworkspacedata | 2914 ----------------- .../xcshareddata/IDEWorkspaceChecks.plist | 8 - .../xcshareddata/WorkspaceSettings.xcsettings | 8 - 3 files changed, 2930 deletions(-) delete mode 100644 swift-algorithm-club.xcworkspace/contents.xcworkspacedata delete mode 100644 swift-algorithm-club.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist delete mode 100644 swift-algorithm-club.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings diff --git a/swift-algorithm-club.xcworkspace/contents.xcworkspacedata b/swift-algorithm-club.xcworkspace/contents.xcworkspacedata deleted file mode 100644 index 03d06d2f7..000000000 --- a/swift-algorithm-club.xcworkspace/contents.xcworkspacedata +++ /dev/null @@ -1,2914 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/swift-algorithm-club.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/swift-algorithm-club.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist deleted file mode 100644 index 18d981003..000000000 --- a/swift-algorithm-club.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +++ /dev/null @@ -1,8 +0,0 @@ - - - - - IDEDidComputeMac32BitWarning - - - diff --git a/swift-algorithm-club.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/swift-algorithm-club.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings deleted file mode 100644 index 08de0be8d..000000000 --- a/swift-algorithm-club.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings +++ /dev/null @@ -1,8 +0,0 @@ - - - - - IDEWorkspaceSharedSettings_AutocreateContextsIfNeeded - - - From ed5fca001429674c1f13557a166a19b73e7ba5e0 Mon Sep 17 00:00:00 2001 From: Kelvin Lau Date: Wed, 30 Oct 2019 14:43:34 -0400 Subject: [PATCH 224/271] Removes travis.yml --- .travis.yml | 55 ----------------------------------------------------- 1 file changed, 55 deletions(-) delete mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 56e205656..000000000 --- a/.travis.yml +++ /dev/null @@ -1,55 +0,0 @@ -language: objective-c -osx_image: xcode9 -# sudo: false - -install: - -- gem install xcpretty-travis-formatter -# - ./install_swiftlint.sh - -script: - -- xcodebuild test -project ./Array2D/Tests/Tests.xcodeproj -scheme Tests | xcpretty -f `xcpretty-travis-formatter` -- xcodebuild test -project ./All-Pairs\ Shortest\ Paths/APSP/APSP.xcodeproj -scheme APSPTests | xcpretty -f `xcpretty-travis-formatter` -- xcodebuild test -project ./AVL\ Tree/Tests/Tests.xcodeproj -scheme Tests | xcpretty -f `xcpretty-travis-formatter` -- xcodebuild test -project ./Binary\ Search/Tests/Tests.xcodeproj -scheme Tests | xcpretty -f `xcpretty-travis-formatter` -- xcodebuild test -project ./Boyer-Moore-Horspool/Tests/Tests.xcodeproj -scheme Tests | xcpretty -f `xcpretty-travis-formatter` -- xcodebuild test -project ./Binary\ Search\ Tree/Solution\ 1/Tests/Tests.xcodeproj -scheme Tests | xcpretty -f `xcpretty-travis-formatter` -- xcodebuild test -project ./Bloom\ Filter/Tests/Tests.xcodeproj -scheme Tests | xcpretty -f `xcpretty-travis-formatter` -- xcodebuild test -project ./Bounded\ Priority\ Queue/Tests/Tests.xcodeproj -scheme Tests | xcpretty -f `xcpretty-travis-formatter` -- xcodebuild test -project ./Breadth-First\ Search/Tests/Tests.xcodeproj -scheme Tests | xcpretty -f `xcpretty-travis-formatter` -- xcodebuild test -project ./Bucket\ Sort/Tests/Tests.xcodeproj -scheme Tests | xcpretty -f `xcpretty-travis-formatter` -- xcodebuild test -project ./B-Tree/Tests/Tests.xcodeproj -scheme Tests | xcpretty -f `xcpretty-travis-formatter` -- xcodebuild test -project ./Comb\ Sort/Tests/Tests.xcodeproj -scheme Tests | xcpretty -f `xcpretty-travis-formatter` -- xcodebuild test -project ./Convex\ Hull/Convex\ Hull.xcodeproj -scheme Tests -destination 'platform=iOS Simulator,name=iPhone 7,OS=11.0' | xcpretty -f `xcpretty-travis-formatter` -- xcodebuild test -project ./Counting\ Sort/Tests/Tests.xcodeproj -scheme Tests | xcpretty -f `xcpretty-travis-formatter` -- xcodebuild test -project ./Depth-First\ Search/Tests/Tests.xcodeproj -scheme Tests | xcpretty -f `xcpretty-travis-formatter` -- xcodebuild test -project ./Graph/Graph.xcodeproj -scheme GraphTests | xcpretty -f `xcpretty-travis-formatter` -- xcodebuild test -project ./Heap/Tests/Tests.xcodeproj -scheme Tests | xcpretty -f `xcpretty-travis-formatter` -- xcodebuild test -project ./Heap\ Sort/Tests/Tests.xcodeproj -scheme Tests | xcpretty -f `xcpretty-travis-formatter` -- xcodebuild test -project ./Insertion\ Sort/Tests/Tests.xcodeproj -scheme Tests | xcpretty -f `xcpretty-travis-formatter` -- xcodebuild test -project ./K-Means/Tests/Tests.xcodeproj -scheme Tests | xcpretty -f `xcpretty-travis-formatter` -- xcodebuild test -project ./Linked\ List/Tests/Tests.xcodeproj -scheme Tests | xcpretty -f `xcpretty-travis-formatter` -- xcodebuild test -project ./Singly\ Linked\ List/Tests/Tests.xcodeproj -scheme Tests | xcpretty -f `xcpretty-travis-formatter` -- xcodebuild test -project ./Longest\ Common\ Subsequence/Tests/Tests.xcodeproj -scheme Tests | xcpretty -f `xcpretty-travis-formatter` -- xcodebuild test -project ./Minimum\ Spanning\ Tree\ \(Unweighted\)/Tests/Tests.xcodeproj -scheme Tests | xcpretty -f `xcpretty-travis-formatter` -- xcodebuild test -project ./Priority\ Queue/Tests/Tests.xcodeproj -scheme Tests | xcpretty -f `xcpretty-travis-formatter` -- xcodebuild test -project ./Queue/Tests/Tests.xcodeproj -scheme Tests | xcpretty -f `xcpretty-travis-formatter` -- xcodebuild test -project ./Quicksort/Tests/Tests-Quicksort.xcodeproj -scheme Test-Quicksort | xcpretty -f `xcpretty-travis-formatter` -- xcodebuild test -project ./Radix\ Sort/Tests/Tests.xcodeproj -scheme Tests | xcpretty -f `xcpretty-travis-formatter` -- xcodebuild test -project ./Rootish\ Array\ Stack/Tests/Tests.xcodeproj -scheme Tests | xcpretty -f `xcpretty-travis-formatter` -- xcodebuild test -project ./Select\ Minimum\ Maximum/Tests/Tests.xcodeproj -scheme Tests | xcpretty -f `xcpretty-travis-formatter` -- xcodebuild test -project ./Selection\ Sort/Tests/Tests.xcodeproj -scheme Tests | xcpretty -f `xcpretty-travis-formatter` -- xcodebuild test -project ./Shell\ Sort/Tests/Tests.xcodeproj -scheme Tests | xcpretty -f `xcpretty-travis-formatter` -- xcodebuild test -project ./Shortest\ Path\ \(Unweighted\)/Tests/Tests.xcodeproj -scheme Tests | xcpretty -f `xcpretty-travis-formatter` -- xcodebuild test -project ./Single-Source\ Shortest\ Paths\ \(Weighted\)/SSSP.xcodeproj -scheme SSSPTests | xcpretty -f `xcpretty-travis-formatter` -- xcodebuild test -project ./Stack/Tests/Tests.xcodeproj -scheme Tests | xcpretty -f `xcpretty-travis-formatter` -- xcodebuild test -project ./Topological\ Sort/Tests/Tests.xcodeproj -scheme Tests | xcpretty -f `xcpretty-travis-formatter` -- xcodebuild test -project ./Treap/Treap/Treap.xcodeproj -scheme Tests | xcpretty -f `xcpretty-travis-formatter` -- xcodebuild test -project ./Palindromes/Test/Test.xcodeproj -scheme Test | xcpretty -f `xcpretty-travis-formatter` -- xcodebuild test -project ./Ternary\ Search\ Tree/Tests/Tests.xcodeproj -scheme Tests | xcpretty -f `xcpretty-travis-formatter` -- xcodebuild test -project ./Karatsuba\ Multiplication/Tests/Tests.xcodeproj -scheme Tests | xcpretty -f `xcpretty-travis-formatter` - -after_success: - -- if [[ "$TRAVIS_BRANCH" == "master" ]]; then ./gfm-render.sh; fi From 7b08311b01bb7f4f2a261286e93e9cf7abe6da1b Mon Sep 17 00:00:00 2001 From: Robert Manson Date: Sun, 3 Nov 2019 17:36:22 -0800 Subject: [PATCH 225/271] Fix infinite recursion in DFS Fixes infinite recursion in the DFS algorithm for topological sort caused by graphs with cycles. For example the following graph would previously have recursed indefinitely `a->b->a`. --- Topological Sort/TopologicalSort1.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Topological Sort/TopologicalSort1.swift b/Topological Sort/TopologicalSort1.swift index 2ad9b51a0..05f1ab887 100644 --- a/Topological Sort/TopologicalSort1.swift +++ b/Topological Sort/TopologicalSort1.swift @@ -1,6 +1,7 @@ extension Graph { private func depthFirstSearch(_ source: Node, visited: inout [Node : Bool]) -> [Node] { var result = [Node]() + visited[source] = true if let adjacencyList = adjacencyList(forNode: source) { for nodeInAdjacencyList in adjacencyList { @@ -10,7 +11,6 @@ extension Graph { } } - visited[source] = true return [source] + result } From 0904c23f746bbbbfc5525ce32cf5c181c1eafe8e Mon Sep 17 00:00:00 2001 From: freak4pc Date: Sat, 9 Nov 2019 18:58:19 +0200 Subject: [PATCH 226/271] Use swapAt for Lomuto's partitioning --- Quicksort/Quicksort.playground/Contents.swift | 4 ++-- Quicksort/README.markdown | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Quicksort/Quicksort.playground/Contents.swift b/Quicksort/Quicksort.playground/Contents.swift index 94d9f8e45..bbe5d9b7d 100644 --- a/Quicksort/Quicksort.playground/Contents.swift +++ b/Quicksort/Quicksort.playground/Contents.swift @@ -42,12 +42,12 @@ func partitionLomuto(_ a: inout [T], low: Int, high: Int) -> Int var i = low for j in low..(_ a: inout [T], low: Int, high: Int) -> Int var i = low for j in low.. Date: Wed, 27 Nov 2019 17:22:04 +0800 Subject: [PATCH 227/271] Update Heap.swift Time complexity of remove() is O(n + log n), which simplifies to O(n). --- Heap/Heap.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Heap/Heap.swift b/Heap/Heap.swift index cf39fb8a5..7560bc7b9 100755 --- a/Heap/Heap.swift +++ b/Heap/Heap.swift @@ -212,7 +212,7 @@ extension Heap where T: Equatable { return nodes.index(where: { $0 == node }) } - /** Removes the first occurrence of a node from the heap. Performance: O(n log n). */ + /** Removes the first occurrence of a node from the heap. Performance: O(n). */ @discardableResult public mutating func remove(node: T) -> T? { if let index = index(of: node) { return remove(at: index) From 7762f6a884daa51e4acdb5677c664bec38273f5c Mon Sep 17 00:00:00 2001 From: TL Date: Fri, 29 Nov 2019 18:52:19 +0800 Subject: [PATCH 228/271] fix: add use case --- Skip-List/SkipList.playground/Contents.swift | 13 +++++++++++++ .../SkipList.playground/Sources/SkipList.swift | 2 +- Skip-List/SkipList.swift | 2 +- 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/Skip-List/SkipList.playground/Contents.swift b/Skip-List/SkipList.playground/Contents.swift index 1b4847c0e..55b9d3a23 100644 --- a/Skip-List/SkipList.playground/Contents.swift +++ b/Skip-List/SkipList.playground/Contents.swift @@ -5,3 +5,16 @@ print("Hello, Swift 4!") // SkipList is ready for Swift 4. // TODO: Add Test + +let k = SkipList() +k.insert(key: 10, data: "10") +k.insert(key: 12, data: "12") +k.insert(key: 13, data: "13") +k.insert(key: 20, data: "20") +k.insert(key: 24, data: "24") + +if let value = k.get(key: 20) { + print(value) +} else { + print("not found!") +} diff --git a/Skip-List/SkipList.playground/Sources/SkipList.swift b/Skip-List/SkipList.playground/Sources/SkipList.swift index f626da0f8..186286977 100644 --- a/Skip-List/SkipList.playground/Sources/SkipList.swift +++ b/Skip-List/SkipList.playground/Sources/SkipList.swift @@ -212,7 +212,7 @@ extension SkipList { } } - func insert(key: Key, data: Payload) { + public func insert(key: Key, data: Payload) { if head != nil { if let node = findNode(key: key) { // replace, in case of key already exists. diff --git a/Skip-List/SkipList.swift b/Skip-List/SkipList.swift index fc635d0f2..8a1959f70 100644 --- a/Skip-List/SkipList.swift +++ b/Skip-List/SkipList.swift @@ -212,7 +212,7 @@ extension SkipList { } } - func insert(key: Key, data: Payload) { + public func insert(key: Key, data: Payload) { if head != nil { if let node = findNode(key: key) { // replace, in case of key already exists. From b513c0331b79a520cd30569913a624eaae8fa7bb Mon Sep 17 00:00:00 2001 From: Kyle Nicol <54515183+TRGoCPftF@users.noreply.github.com> Date: Tue, 10 Dec 2019 12:30:45 -0500 Subject: [PATCH 229/271] Update simann_example.swift Corrected definition where shuffle() was invoking self.shuffle() instead of self.tour.shuffle(), which would left the example in a infinite loop of shuffle() invocation --- Simulated annealing/simann_example.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Simulated annealing/simann_example.swift b/Simulated annealing/simann_example.swift index 0e07e0024..e7933c89a 100644 --- a/Simulated annealing/simann_example.swift +++ b/Simulated annealing/simann_example.swift @@ -138,7 +138,7 @@ extension Tour { } func shuffle() { - self.shuffle() + self.tour.shuffle() } } From 809cb974dc0b105407500f42e675c55f55e1588b Mon Sep 17 00:00:00 2001 From: "G. Moraleda" Date: Wed, 22 Jan 2020 17:51:05 +0100 Subject: [PATCH 230/271] Typos corrected --- Count Occurrences/README.markdown | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Count Occurrences/README.markdown b/Count Occurrences/README.markdown index 297bc4b0f..95f020e90 100644 --- a/Count Occurrences/README.markdown +++ b/Count Occurrences/README.markdown @@ -25,10 +25,10 @@ In code this looks as follows: func countOccurrences(of key: T, in array: [T]) -> Int { var leftBoundary: Int { var low = 0 - var high = a.count + var high = array.count while low < high { let midIndex = low + (high - low)/2 - if a[midIndex] < key { + if array[midIndex] < key { low = midIndex + 1 } else { high = midIndex @@ -39,10 +39,10 @@ func countOccurrences(of key: T, in array: [T]) -> Int { var rightBoundary: Int { var low = 0 - var high = a.count + var high = array.count while low < high { let midIndex = low + (high - low)/2 - if a[midIndex] > key { + if array[midIndex] > key { high = midIndex } else { low = midIndex + 1 @@ -62,7 +62,7 @@ To test this algorithm, copy the code to a playground and then do: ```swift let a = [ 0, 1, 1, 3, 3, 3, 3, 6, 8, 10, 11, 11 ] -countOccurrencesOfKey(3, inArray: a) // returns 4 +countOccurrences(of: 3, in: a) // returns 4 ``` > **Remember:** If you use your own array, make sure it is sorted first! From 8a7db67f4f0e1706a3a91054f1b7aecc6ac95761 Mon Sep 17 00:00:00 2001 From: "G. Moraleda" Date: Wed, 22 Jan 2020 19:57:53 +0100 Subject: [PATCH 231/271] Update README.markdown --- Count Occurrences/README.markdown | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/Count Occurrences/README.markdown b/Count Occurrences/README.markdown index 95f020e90..2e48d1020 100644 --- a/Count Occurrences/README.markdown +++ b/Count Occurrences/README.markdown @@ -22,13 +22,13 @@ The trick is to use two binary searches, one to find where the `3`s start (the l In code this looks as follows: ```swift -func countOccurrences(of key: T, in array: [T]) -> Int { +func countOccurrences(of key: T, in a: [T]) -> Int { var leftBoundary: Int { var low = 0 - var high = array.count + var high = a.count while low < high { let midIndex = low + (high - low)/2 - if array[midIndex] < key { + if a[midIndex] < key { low = midIndex + 1 } else { high = midIndex @@ -39,10 +39,10 @@ func countOccurrences(of key: T, in array: [T]) -> Int { var rightBoundary: Int { var low = 0 - var high = array.count + var high = a.count while low < high { let midIndex = low + (high - low)/2 - if array[midIndex] > key { + if a[midIndex] > key { high = midIndex } else { low = midIndex + 1 @@ -55,7 +55,9 @@ func countOccurrences(of key: T, in array: [T]) -> Int { } ``` -Notice that the variables `leftBoundary` and `rightBoundary` are very similar to the [binary search](../Binary%20Search/) algorithm. The big difference is that they don't stop when they find the search key, but keep going. Also, notice that we constrain the type `T` to be Comparable so that the algorithm can be applied to an array of Strings, Ints or other types that conform to the Swift Comparable protocol. +Notice that the variables `leftBoundary` and `rightBoundary` are very similar to the [binary search](../Binary%20Search/) algorithm. The big difference is that they don't stop when they find the search key, but keep going. Also, notice that we constrain the type `T` to be Comparable so that the algorithm can be applied to an + +y of Strings, Ints or other types that conform to the Swift Comparable protocol. To test this algorithm, copy the code to a playground and then do: From 467503c623c0fa781ea337b68a2ee5251d9a20bc Mon Sep 17 00:00:00 2001 From: "G. Moraleda" Date: Wed, 22 Jan 2020 19:58:38 +0100 Subject: [PATCH 232/271] Update README.markdown --- Count Occurrences/README.markdown | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/Count Occurrences/README.markdown b/Count Occurrences/README.markdown index 2e48d1020..4deb9990e 100644 --- a/Count Occurrences/README.markdown +++ b/Count Occurrences/README.markdown @@ -55,9 +55,7 @@ func countOccurrences(of key: T, in a: [T]) -> Int { } ``` -Notice that the variables `leftBoundary` and `rightBoundary` are very similar to the [binary search](../Binary%20Search/) algorithm. The big difference is that they don't stop when they find the search key, but keep going. Also, notice that we constrain the type `T` to be Comparable so that the algorithm can be applied to an - -y of Strings, Ints or other types that conform to the Swift Comparable protocol. +Notice that the variables `leftBoundary` and `rightBoundary` are very similar to the [binary search](../Binary%20Search/) algorithm. The big difference is that they don't stop when they find the search key, but keep going. Also, notice that we constrain the type `T` to be Comparable so that the algorithm can be applied to an array of Strings, Ints or other types that conform to the Swift Comparable protocol. To test this algorithm, copy the code to a playground and then do: From 43181f5b4c8790fa887c4a6bd5ea8e94b0279eb5 Mon Sep 17 00:00:00 2001 From: Satveer Singh Date: Thu, 6 Feb 2020 19:30:24 +1100 Subject: [PATCH 233/271] Fix typo in Heap Sort README lg -> log --- Heap Sort/README.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Heap Sort/README.markdown b/Heap Sort/README.markdown index a45dad6f9..5bec58626 100644 --- a/Heap Sort/README.markdown +++ b/Heap Sort/README.markdown @@ -42,7 +42,7 @@ As you can see, the largest items are making their way to the back. We repeat th > **Note:** This process is very similar to [selection sort](../Selection%20Sort/), which repeatedly looks for the minimum item in the remainder of the array. Extracting the minimum or maximum value is what heaps are good at. -Performance of heap sort is **O(n lg n)** in best, worst, and average case. Because we modify the array directly, heap sort can be performed in-place. But it is not a stable sort: the relative order of identical elements is not preserved. +Performance of heap sort is **O(n log n)** in best, worst, and average case. Because we modify the array directly, heap sort can be performed in-place. But it is not a stable sort: the relative order of identical elements is not preserved. Here's how you can implement heap sort in Swift: From f664af1f502ec7f6692e8dcb34d5848ce3af4e60 Mon Sep 17 00:00:00 2001 From: "G. Moraleda" Date: Mon, 10 Feb 2020 20:01:47 +0100 Subject: [PATCH 234/271] Renamed array --- Count Occurrences/README.markdown | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Count Occurrences/README.markdown b/Count Occurrences/README.markdown index 4deb9990e..8e935ea58 100644 --- a/Count Occurrences/README.markdown +++ b/Count Occurrences/README.markdown @@ -22,10 +22,10 @@ The trick is to use two binary searches, one to find where the `3`s start (the l In code this looks as follows: ```swift -func countOccurrences(of key: T, in a: [T]) -> Int { +func countOccurrences(of key: T, in array: [T]) -> Int { var leftBoundary: Int { var low = 0 - var high = a.count + var high = array.count while low < high { let midIndex = low + (high - low)/2 if a[midIndex] < key { @@ -39,7 +39,7 @@ func countOccurrences(of key: T, in a: [T]) -> Int { var rightBoundary: Int { var low = 0 - var high = a.count + var high = array.count while low < high { let midIndex = low + (high - low)/2 if a[midIndex] > key { From 901aaeac47c2275d0e5facbf9c5525882eb4f7ea Mon Sep 17 00:00:00 2001 From: Paul Anguiano Date: Thu, 5 Mar 2020 18:10:39 -0800 Subject: [PATCH 235/271] Modified Trie to add prefix support to boolean contains(), plus unit tests. --- Trie/Trie/Trie/Trie.swift | 9 ++++++--- Trie/Trie/TrieTests/TrieTests.swift | 27 ++++++++++++++++++++++++++- 2 files changed, 32 insertions(+), 4 deletions(-) diff --git a/Trie/Trie/Trie/Trie.swift b/Trie/Trie/Trie/Trie.swift index accc7b61c..3d5031cf3 100644 --- a/Trie/Trie/Trie/Trie.swift +++ b/Trie/Trie/Trie/Trie.swift @@ -117,9 +117,12 @@ extension Trie { /// Determines whether a word is in the trie. /// - /// - Parameter word: the word to check for + /// - Parameters: + /// - word: the word to check for + /// - matchPrefix: whether the search word should match + /// if it is only a prefix of other nodes in the trie /// - Returns: true if the word is present, false otherwise. - func contains(word: String) -> Bool { + func contains(word: String, matchPrefix: Bool = false) -> Bool { guard !word.isEmpty else { return false } @@ -130,7 +133,7 @@ extension Trie { } currentNode = childNode } - return currentNode.isTerminating + return matchPrefix || currentNode.isTerminating } /// Attempts to walk to the last node of a word. The diff --git a/Trie/Trie/TrieTests/TrieTests.swift b/Trie/Trie/TrieTests/TrieTests.swift index 0c5bc69c6..59da2cd9b 100644 --- a/Trie/Trie/TrieTests/TrieTests.swift +++ b/Trie/Trie/TrieTests/TrieTests.swift @@ -167,7 +167,8 @@ class TrieTests: XCTestCase { let trieCopy = NSKeyedUnarchiver.unarchiveObject(withFile: filePath) as? Trie XCTAssertEqual(trieCopy?.count, trie.count) } - + + /// Tests whether word prefixes are properly found and returned. func testFindWordsWithPrefix() { let trie = Trie() trie.insert(word: "test") @@ -190,4 +191,28 @@ class TrieTests: XCTestCase { let wordsUpperCase = trie.findWordsWithPrefix(prefix: "Te") XCTAssertEqual(wordsUpperCase.sorted(), ["team", "test"]) } + + /// Tests whether word prefixes are properly detected on a boolean contains() check. + func testContainsWordMatchPrefix() { + let trie = Trie() + trie.insert(word: "test") + trie.insert(word: "another") + trie.insert(word: "exam") + let wordsAll = trie.contains(word: "", matchPrefix: true) + XCTAssertEqual(wordsAll, true) + let words = trie.contains(word: "ex", matchPrefix: true) + XCTAssertEqual(words, true) + trie.insert(word: "examination") + let words2 = trie.contains(word: "exam", matchPrefix: true) + XCTAssertEqual(words2, true) + let noWords = trie.contains(word: "tee", matchPrefix: true) + XCTAssertEqual(noWords, false) + let unicodeWord = "😬😎" + trie.insert(word: unicodeWord) + let wordsUnicode = trie.contains(word: "😬", matchPrefix: true) + XCTAssertEqual(wordsUnicode, true) + trie.insert(word: "Team") + let wordsUpperCase = trie.contains(word: "Te", matchPrefix: true) + XCTAssertEqual(wordsUpperCase, true) + } } From 510f3da1a0e445c3c1ec4aec69f1731a86acfbc4 Mon Sep 17 00:00:00 2001 From: Mick Bennett Date: Fri, 27 Mar 2020 00:00:03 -0700 Subject: [PATCH 236/271] updated depricated hashable values to hash into methods --- Graph/Graph/Edge.swift | 10 ++++------ Graph/Graph/Vertex.swift | 5 +++-- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/Graph/Graph/Edge.swift b/Graph/Graph/Edge.swift index ac5ed6a25..b69937895 100644 --- a/Graph/Graph/Edge.swift +++ b/Graph/Graph/Edge.swift @@ -29,12 +29,10 @@ extension Edge: CustomStringConvertible { extension Edge: Hashable { - public var hashValue: Int { - var string = "\(from.description)\(to.description)" - if weight != nil { - string.append("\(weight!)") - } - return string.hashValue + public func hash(into hasher: inout Hasher) { + hasher.combine(from.description) + hasher.combine(to.description) + hasher.combine(weight) } } diff --git a/Graph/Graph/Vertex.swift b/Graph/Graph/Vertex.swift index 758a367bb..47499dcc6 100644 --- a/Graph/Graph/Vertex.swift +++ b/Graph/Graph/Vertex.swift @@ -24,8 +24,9 @@ extension Vertex: CustomStringConvertible { extension Vertex: Hashable { - public var hashValue: Int { - return "\(data)\(index)".hashValue + public func hash(into hasher: inout Hasher) { + hasher.combine(data) + hasher.combine(index) } } From 47356447f47fc353cb95dcdcc9a4d296b1a1b816 Mon Sep 17 00:00:00 2001 From: Mick Bennett Date: Thu, 9 Apr 2020 16:47:58 -0700 Subject: [PATCH 237/271] updated lcs string extension to access string directly --- .../Contents.swift | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Longest Common Subsequence/LongestCommonSubsequence.playground/Contents.swift b/Longest Common Subsequence/LongestCommonSubsequence.playground/Contents.swift index c8d413e7f..0e78b7043 100644 --- a/Longest Common Subsequence/LongestCommonSubsequence.playground/Contents.swift +++ b/Longest Common Subsequence/LongestCommonSubsequence.playground/Contents.swift @@ -1,4 +1,4 @@ -// last checked with Xcode 9.0b4 +// last checked with Xcode 11.4 #if swift(>=4.0) print("Hello, Swift 4!") #endif @@ -7,10 +7,10 @@ extension String { public func longestCommonSubsequence(_ other: String) -> String { func lcsLength(_ other: String) -> [[Int]] { - var matrix = [[Int]](repeating: [Int](repeating: 0, count: other.characters.count+1), count: self.characters.count+1) + var matrix = [[Int]](repeating: [Int](repeating: 0, count: other.count+1), count: self.count+1) - for (i, selfChar) in self.characters.enumerated() { - for (j, otherChar) in other.characters.enumerated() { + for (i, selfChar) in self.enumerated() { + for (j, otherChar) in other.enumerated() { if otherChar == selfChar { matrix[i+1][j+1] = matrix[i][j] + 1 } else { @@ -22,8 +22,8 @@ extension String { } func backtrack(_ matrix: [[Int]]) -> String { - var i = self.characters.count - var j = other.characters.count + var i = self.count + var j = other.count var charInSequence = self.endIndex var lcs = String() @@ -41,7 +41,7 @@ extension String { lcs.append(self[charInSequence]) } } - return String(lcs.characters.reversed()) + return String(lcs.reversed()) } return backtrack(lcsLength(other)) From 5b0861c2eca8ec37ed3f2667ada5de7e850cd75e Mon Sep 17 00:00:00 2001 From: Azhar Anwar Date: Tue, 28 Apr 2020 15:52:03 +0530 Subject: [PATCH 238/271] fixes: typo and punctuation --- Shuffle/README.markdown | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Shuffle/README.markdown b/Shuffle/README.markdown index 5a2a07a98..d9c35868a 100644 --- a/Shuffle/README.markdown +++ b/Shuffle/README.markdown @@ -37,7 +37,7 @@ This code works just fine but it's not very efficient. Removing an element from ## The Fisher-Yates / Knuth shuffle -Here is a much improved version of the shuffle algorithm: +Here is a much-improved version of the shuffle algorithm: ```swift extension Array { @@ -52,7 +52,7 @@ extension Array { } ``` -Again, this picks objects at random. In the naive version we placed those objects into a new temporary array so we could keep track of which objects were already shuffled and which still remained to be done. In this improved algorithm, however, we'll move the shuffled objects to the end of the original array. +Again, this picks objects at random. In the naive version, we placed those objects into a new temporary array so we could keep track of which objects were already shuffled and which still remained to be done. In this improved algorithm, however, we'll move the shuffled objects to the end of the original array. Let's walk through the example. We have the array: @@ -116,7 +116,7 @@ The `shuffledArray()` function first creates a new array with `n` zeros. Then it For this function, `The condition that checks if j ≠ i may be omitted in languages that have no problems accessing uninitialized array values, and for which assigning is cheaper than comparing.`, you can check it in wiki. And also remove checking logic will optimise performance. -The algoritm is quite clever and I suggest you walk through an example yourself, either on paper or in the playground. (Hint: Again it splits the array into two regions.) +The algorithm is quite clever and I suggest you walk through an example yourself, either on paper or in the playground. (Hint: Again it splits the array into two regions.) ## See also From 409ffd6921441afb56a7ea68c73a0f2c9516c809 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sarp=20G=C3=BCney=20Ba=C5=9Faraner?= Date: Thu, 7 May 2020 10:35:45 +0300 Subject: [PATCH 239/271] fix typo Dinstance -> Distance --- HaversineDistance/HaversineDistance.playground/Contents.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/HaversineDistance/HaversineDistance.playground/Contents.swift b/HaversineDistance/HaversineDistance.playground/Contents.swift index 3d8d60f54..ed89b4462 100644 --- a/HaversineDistance/HaversineDistance.playground/Contents.swift +++ b/HaversineDistance/HaversineDistance.playground/Contents.swift @@ -1,6 +1,6 @@ import UIKit -func haversineDinstance(la1: Double, lo1: Double, la2: Double, lo2: Double, radius: Double = 6367444.7) -> Double { +func haversineDistance(la1: Double, lo1: Double, la2: Double, lo2: Double, radius: Double = 6367444.7) -> Double { let haversin = { (angle: Double) -> Double in return (1 - cos(angle))/2 @@ -27,4 +27,4 @@ let amsterdam = (52.3702, 4.8952) let newYork = (40.7128, -74.0059) // Google says it's 5857 km so our result is only off by 2km which could be due to all kinds of things, not sure how google calculates the distance or which latitude and longitude google uses to calculate the distance. -haversineDinstance(la1: amsterdam.0, lo1: amsterdam.1, la2: newYork.0, lo2: newYork.1) +haversineDistance(la1: amsterdam.0, lo1: amsterdam.1, la2: newYork.0, lo2: newYork.1) From 7a77f3fa8abbdc0ee68b77b84d56b3e1eaf61087 Mon Sep 17 00:00:00 2001 From: L Rettberg Date: Sat, 9 May 2020 11:57:00 -0500 Subject: [PATCH 240/271] Update Readme for code modification Update to reflect alternative of using .isMultiple(of:) method instead of modulo (%) operator --- Fizz Buzz/README.markdown | 97 ++++++++++++++++++++++++++++----------- 1 file changed, 69 insertions(+), 28 deletions(-) diff --git a/Fizz Buzz/README.markdown b/Fizz Buzz/README.markdown index 8c250da27..be516bd46 100644 --- a/Fizz Buzz/README.markdown +++ b/Fizz Buzz/README.markdown @@ -16,46 +16,48 @@ The modulus operator `%` is the key to solving fizz buzz. The modulus operator returns the remainder after an integer division. Here is an example of the modulus operator: -| Division | Division Result | Modulus | Modulus Result | -| ------------- | -------------------------- | --------------- | ---------------:| -| 1 / 3 | 0 with a remainder of 3 | 1 % 3 | 1 | -| 5 / 3 | 1 with a remainder of 2 | 5 % 3 | 2 | -| 16 / 3 | 5 with a remainder of 1 | 16 % 3 | 1 | +| Division | Division Result | Modulus | Modulus Result| +| ----------- | --------------------- | ------------- | :-----------: | +| 1 / 3 | 0 with a remainder of 3 | 1 % 3 | 1 | +| 5 / 3 | 1 with a remainder of 2 | 5 % 3 | 2 | +| 16 / 3 | 5 with a remainder of 1 | 16 % 3 | 1 | A common approach to determine if a number is even or odd is to use the modulus operator: -| Modulus | Result | Swift Code | Swift Code Result | Comment | -| ------------- | ---------------:| ------------------------------- | -----------------:| --------------------------------------------- | -| 6 % 2 | 0 | `let isEven = (number % 2 == 0)` | `true` | If a number is divisible by 2 it is *even* | -| 5 % 2 | 1 | `let isOdd = (number % 2 != 0)` | `true` | If a number is not divisible by 2 it is *odd* | +| Modulus | Result | Swift Code | Swift Code
    Result | Comment | +| -------- | :-----:| -------------------------------- | :----------------:| --------------------------------------------- | +| 6 % 2 | 0 | `let isEven = (number % 2 == 0)` | `true` | If a number is divisible by 2 it is *even* | +| 5 % 2 | 1 | `let isOdd = (number % 2 != 0)` | `true` | If a number is not divisible by 2 it is *odd* | + +Alternatively, Swift's built in function .isMultiple(of:) can be used, i.e. 6.isMultiple(of: 2) will return true, 5.isMultiple(of: 2) will return false ## Solving fizz buzz -Now we can use the modulus operator `%` to solve fizz buzz. +Now we can use the modulus operator `%` or .isMultiple(of:) method to solve fizz buzz. Finding numbers divisible by three: -| Modulus | Modulus Result | Swift Code | Swift Code Result | -| ------- | --------------:| ------------- |------------------:| -| 1 % 3 | 1 | `1 % 3 == 0` | `false` | -| 2 % 3 | 2 | `2 % 3 == 0` | `false` | -| 3 % 3 | 0 | `3 % 3 == 0` | `true` | -| 4 % 3 | 1 | `4 % 3 == 0` | `false` | +| Modulus | Modulus
    Result | Swift Code
    using Modulo | Swift Code
    using .isMultiple(of:) | Swift Code
    Result | +| ------- | :---------------: | -------------------------- | ------------------------------------ | ------------------- | +|1 % 3 | 1 | `1 % 3 == 0` | `1.isMultiple(of: 3)` | `false` | +|2 % 3 | 2 | `2 % 3 == 0` | `2.isMultiple(of: 3)` | `false` | +|3 % 3 | 0 | `3 % 3 == 0` | `3.isMultiple(of: 3)` | `true` | +|4 % 3 | 1 | `4 % 3 == 0` | `4.isMultiple(of: 3)` | `false` | Finding numbers divisible by five: -| Modulus | Modulus Result | Swift Code | Swift Code Result | -| ------- | --------------:| ------------- |------------------:| -| 1 % 5 | 1 | `1 % 5 == 0` | `false` | -| 2 % 5 | 2 | `2 % 5 == 0` | `false` | -| 3 % 5 | 3 | `3 % 5 == 0` | `false` | -| 4 % 5 | 4 | `4 % 5 == 0` | `false` | -| 5 % 5 | 0 | `5 % 5 == 0` | `true` | -| 6 % 5 | 1 | `6 % 5 == 0` | `false` | +| Modulus | Modulus
    Result | Swift Code
    using Modulo | Swift Code
    using .isMultiple(of:) | Swift Code
    Result | +| ------- | :---------------: | -------------------------- | ------------------------------------ | -------------------- | +| 1 % 5 | 1 | `1 % 5 == 0` | `1.isMultiple(of: 5)` | `false` | +| 2 % 5 | 2 | `2 % 5 == 0` | `2.isMultiple(of: 5)` | `false` | +| 3 % 5 | 3 | `3 % 5 == 0` | `3.isMultiple(of: 5)` | `false` | +| 4 % 5 | 4 | `4 % 5 == 0` | `4.isMultiple(of: 5)` | `false` | +| 5 % 5 | 0 | `5 % 5 == 0` | `5.isMultiple(of: 5)` | `true` | +| 6 % 5 | 1 | `6 % 5 == 0` | `6.isMultiple(of: 5)` | `false` | ## The code -Here is a simple implementation in Swift: +Here is a simple implementation in Swift using Modulus approach ```swift func fizzBuzz(_ numberOfTurns: Int) { @@ -79,7 +81,31 @@ func fizzBuzz(_ numberOfTurns: Int) { } ``` -Put this code in a playground and test it like so: +Here is simple implementation in Swift using .isMultiple(of:) and switch statement + +```swift +func fizzBuzz(_ numberOfTurns: Int) { + guard numberOfTurns >= 1 else { + print("Number of turns must be >= 1") + return + } + + for i in 1...numberOfTurns { + switch (i.isMultiple(of: 3), i.isMultiple(of: 5)) { + case (false, false): + print("\(i)") + case (true, false): + print("Fizz") + case (false, true): + print("Buzz") + case (true, true): + print("Fizz Buzz") + } + } +} +``` + +Put either code in a playground and test it like so: ```swift fizzBuzz(15) @@ -87,10 +113,25 @@ fizzBuzz(15) This will output: - 1, 2, Fizz, 4, Buzz, Fizz, 7, 8, Fizz, Buzz, 11, Fizz, 13, 14, Fizz Buzz +1 +2 +Fizz +4 +Buzz +Fizz +7 +8 +Fizz +Buzz +11 +Fizz +13 +14 +Fizz Buzz ## See also [Fizz buzz on Wikipedia](https://en.wikipedia.org/wiki/Fizz_buzz) -*Written by [Chris Pilcher](https://github.com/chris-pilcher)* +*Originally written by [Chris Pilcher](https://github.com/chris-pilcher)*
    +*Updated by [Lance Rettberg](https://github.com/l-rettberg)* From 99d769d03c0cfee1b92b63aeeb1b203811eaddc8 Mon Sep 17 00:00:00 2001 From: L Rettberg Date: Sat, 9 May 2020 12:02:06 -0500 Subject: [PATCH 241/271] Update FizzBuzz Update to 1) add guard, 2) use .isMultiple(of:), 3) use switch statement --- Fizz Buzz/FizzBuzz.swift | 32 +++++++++++++++++--------------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/Fizz Buzz/FizzBuzz.swift b/Fizz Buzz/FizzBuzz.swift index b6bb410e7..704ea7c6b 100644 --- a/Fizz Buzz/FizzBuzz.swift +++ b/Fizz Buzz/FizzBuzz.swift @@ -1,19 +1,21 @@ -func fizzBuzz(_ numberOfTurns: Int) { - for i in 1...numberOfTurns { - var result = "" +// Updated for Xcode Version 11.4.1 (11E503a) - if i % 3 == 0 { - result += "Fizz" +func fizzBuzz2(_ numberOfTurns: Int) { + guard numberOfTurns >= 1 else { + print("Number of turns must be >= 1") + return } - - if i % 5 == 0 { - result += (result.isEmpty ? "" : " ") + "Buzz" - } - - if result.isEmpty { - result += "\(i)" + + for i in 1...numberOfTurns { + switch (i.isMultiple(of: 3), i.isMultiple(of: 5)) { + case (false, false): + print("\(i)") + case (true, false): + print("Fizz") + case (false, true): + print("Buzz") + case (true, true): + print("Fizz Buzz") + } } - - print(result) - } } From 71431b12042a2dc17eb9c170a9fa5c731942462d Mon Sep 17 00:00:00 2001 From: L Rettberg Date: Sat, 9 May 2020 12:09:54 -0500 Subject: [PATCH 242/271] Update --- Fizz Buzz/FizzBuzz.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Fizz Buzz/FizzBuzz.swift b/Fizz Buzz/FizzBuzz.swift index 704ea7c6b..2e66b26f4 100644 --- a/Fizz Buzz/FizzBuzz.swift +++ b/Fizz Buzz/FizzBuzz.swift @@ -1,6 +1,6 @@ // Updated for Xcode Version 11.4.1 (11E503a) -func fizzBuzz2(_ numberOfTurns: Int) { +func fizzBuzz(_ numberOfTurns: Int) { guard numberOfTurns >= 1 else { print("Number of turns must be >= 1") return From f94bccc68d017bbc61cb774f7642dd25b25f1d4a Mon Sep 17 00:00:00 2001 From: L Rettberg Date: Sat, 9 May 2020 14:41:39 -0500 Subject: [PATCH 243/271] Updates to 1) add guard, 2) use .isMultiple(of:) and 3) use switch statement --- Fizz Buzz/FizzBuzz.playground/Contents.swift | 34 ++++++++++---------- Fizz Buzz/FizzBuzz.swift | 4 +-- 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/Fizz Buzz/FizzBuzz.playground/Contents.swift b/Fizz Buzz/FizzBuzz.playground/Contents.swift index ae966bbcc..2ab13b362 100644 --- a/Fizz Buzz/FizzBuzz.playground/Contents.swift +++ b/Fizz Buzz/FizzBuzz.playground/Contents.swift @@ -1,23 +1,23 @@ -// last checked with Xcode 10.0 (10A255) +// Last checked with Xcode Version 11.4.1 (11E503a) func fizzBuzz(_ numberOfTurns: Int) { - for i in 1...numberOfTurns { - var result = "" - - if i % 3 == 0 { - result += "Fizz" + guard numberOfTurns >= 1 else { + print("Number of turns must be >= 1") + return } - - if i % 5 == 0 { - result += (result.isEmpty ? "" : " ") + "Buzz" + + for i in 1...numberOfTurns { + switch (i.isMultiple(of: 3), i.isMultiple(of: 5)) { + case (false, false): + print("\(i)") + case (true, false): + print("Fizz") + case (false, true): + print("Buzz") + case (true, true): + print("Fizz Buzz") + } } - - if result.isEmpty { - result += "\(i)" - } - - print(result) - } } -fizzBuzz(100) +fizzBuzz(15) diff --git a/Fizz Buzz/FizzBuzz.swift b/Fizz Buzz/FizzBuzz.swift index 2e66b26f4..bf753e648 100644 --- a/Fizz Buzz/FizzBuzz.swift +++ b/Fizz Buzz/FizzBuzz.swift @@ -1,4 +1,4 @@ -// Updated for Xcode Version 11.4.1 (11E503a) +// Last checked with Xcode Version 11.4.1 (11E503a) func fizzBuzz(_ numberOfTurns: Int) { guard numberOfTurns >= 1 else { @@ -18,4 +18,4 @@ func fizzBuzz(_ numberOfTurns: Int) { print("Fizz Buzz") } } -} +} \ No newline at end of file From 6a9ec9628099601714655ad42237d8948b2cfc05 Mon Sep 17 00:00:00 2001 From: L Rettberg Date: Sat, 9 May 2020 16:45:31 -0500 Subject: [PATCH 244/271] Remove file --- Fizz Buzz/FizzBuzz.playground/contents.xcplayground | 4 ---- 1 file changed, 4 deletions(-) delete mode 100644 Fizz Buzz/FizzBuzz.playground/contents.xcplayground diff --git a/Fizz Buzz/FizzBuzz.playground/contents.xcplayground b/Fizz Buzz/FizzBuzz.playground/contents.xcplayground deleted file mode 100644 index 5da2641c9..000000000 --- a/Fizz Buzz/FizzBuzz.playground/contents.xcplayground +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file From e3b3126f819ec57b9759cd4b80f639b1d39b440a Mon Sep 17 00:00:00 2001 From: L Rettberg Date: Sat, 9 May 2020 16:47:18 -0500 Subject: [PATCH 245/271] Delete IDEWorkspaceChecks.plist --- .../xcshareddata/IDEWorkspaceChecks.plist | 8 -------- 1 file changed, 8 deletions(-) delete mode 100644 Fizz Buzz/FizzBuzz.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist diff --git a/Fizz Buzz/FizzBuzz.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Fizz Buzz/FizzBuzz.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist deleted file mode 100644 index 18d981003..000000000 --- a/Fizz Buzz/FizzBuzz.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +++ /dev/null @@ -1,8 +0,0 @@ - - - - - IDEDidComputeMac32BitWarning - - - From 51b0c2b5a2abed1a90241e64869ccd173b54a1e7 Mon Sep 17 00:00:00 2001 From: L Rettberg Date: Sat, 9 May 2020 16:47:30 -0500 Subject: [PATCH 246/271] Delete contents.xcworkspacedata --- .../playground.xcworkspace/contents.xcworkspacedata | 7 ------- 1 file changed, 7 deletions(-) delete mode 100644 Fizz Buzz/FizzBuzz.playground/playground.xcworkspace/contents.xcworkspacedata diff --git a/Fizz Buzz/FizzBuzz.playground/playground.xcworkspace/contents.xcworkspacedata b/Fizz Buzz/FizzBuzz.playground/playground.xcworkspace/contents.xcworkspacedata deleted file mode 100644 index 919434a62..000000000 --- a/Fizz Buzz/FizzBuzz.playground/playground.xcworkspace/contents.xcworkspacedata +++ /dev/null @@ -1,7 +0,0 @@ - - - - - From 4617d9401be60101c12e100f428c0b460de0a210 Mon Sep 17 00:00:00 2001 From: jinthislife <8064873+jinthislife@users.noreply.github.com> Date: Mon, 11 May 2020 15:30:38 +1000 Subject: [PATCH 247/271] Update README.markdown remove duplicate parameter --- Binary Search Tree/README.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Binary Search Tree/README.markdown b/Binary Search Tree/README.markdown index 0b382f204..57d1f4bff 100644 --- a/Binary Search Tree/README.markdown +++ b/Binary Search Tree/README.markdown @@ -557,7 +557,7 @@ As a result, doing `tree.search(100)` gives nil. You can check whether a tree is a valid binary search tree with the following method: ```swift - public func isBST(minValue minValue: T, maxValue: T) -> Bool { + public func isBST(minValue: T, maxValue: T) -> Bool { if value < minValue || value > maxValue { return false } let leftBST = left?.isBST(minValue: minValue, maxValue: value) ?? true let rightBST = right?.isBST(minValue: value, maxValue: maxValue) ?? true From bf3f3d5d690fe0a6e3cd7fc549781551477a8c6b Mon Sep 17 00:00:00 2001 From: Jagdeep Matharu Date: Sun, 31 May 2020 19:54:14 -0400 Subject: [PATCH 248/271] Updating Counting sort for stability --- Counting Sort/CountingSort.playground/Contents.swift | 7 ++++++- Counting Sort/CountingSort.swift | 5 ++++- Counting Sort/README.markdown | 7 +++++-- 3 files changed, 15 insertions(+), 4 deletions(-) diff --git a/Counting Sort/CountingSort.playground/Contents.swift b/Counting Sort/CountingSort.playground/Contents.swift index dc375512a..839b16bc8 100644 --- a/Counting Sort/CountingSort.playground/Contents.swift +++ b/Counting Sort/CountingSort.playground/Contents.swift @@ -29,12 +29,17 @@ func countingSort(array: [Int]) throws -> [Int] { // Step 3 // Place the element in the final array as per the number of elements before it + // Loop through the array in reverse to keep the stability of the new array + // (i.e. 7, is at index 3 and 6, thus in sortedArray the position of 7 at index 3 should be before 7 at index 6 var sortedArray = [Int](repeating: 0, count: array.count) - for element in array { + for index in stride(from: array.count - 1, through: 0, by: -1) { + let element = array[index] countArray[element] -= 1 sortedArray[countArray[element]] = element } + return sortedArray } try countingSort(array: [10, 9, 8, 7, 1, 2, 7, 3]) + diff --git a/Counting Sort/CountingSort.swift b/Counting Sort/CountingSort.swift index 725a634a4..68dcf5c0d 100644 --- a/Counting Sort/CountingSort.swift +++ b/Counting Sort/CountingSort.swift @@ -29,8 +29,11 @@ func countingSort(_ array: [Int])-> [Int] { // Step 3 // Place the element in the final array as per the number of elements before it + // Loop through the array in reverse to keep the stability of the new sorted array + // (For Example: 7 is at index 3 and 6, thus in sortedArray the position of 7 at index 3 should be before 7 at index 6 var sortedArray = [Int](repeating: 0, count: array.count) - for element in array { + for index in stride(from: array.count - 1, through: 0, by: -1) { + let element = array[index] countArray[element] -= 1 sortedArray[countArray[element]] = element } diff --git a/Counting Sort/README.markdown b/Counting Sort/README.markdown index 959becc8c..93d6635bd 100644 --- a/Counting Sort/README.markdown +++ b/Counting Sort/README.markdown @@ -50,7 +50,9 @@ The code for step 2 is: ### Step 3: -This is the last step in the algorithm. Each element in the original array is placed at the position defined by the output of step 2. For example, the number 10 would be placed at an index of 7 in the output array. Also, as you place the elements you need to reduce the count by 1 as those many elements are reduced from the array. +This is the last step in the algorithm. Each element in the original array is placed at the position defined by the output of step 2. For example, the number 10 would be placed at an index of 7 in the output array. Also, as you place the elements you need to reduce the count by 1 as those many elements are reduced from the array. +We also have to loop through the array in reverse to keep the stability of the new sorted array. +For Example: 7 is at index 3 and 6, thus in sortedArray the position of 7 at index 3 should be before 7 at index 6. The final output would be: @@ -63,7 +65,8 @@ Here is the code for this final step: ```swift var sortedArray = [Int](repeating: 0, count: array.count) - for element in array { + for index in stride(from: array.count - 1, through: 0, by: -1) { + let element = array[index] countArray[element] -= 1 sortedArray[countArray[element]] = element } From d06b7e3c5e45a65b2f275a7dd81bfc77520788c6 Mon Sep 17 00:00:00 2001 From: Jagdeep Matharu Date: Sun, 31 May 2020 19:54:43 -0400 Subject: [PATCH 249/271] Updating Counting sort tests project to support Swift 5 --- .../xcshareddata/IDEWorkspaceChecks.plist | 8 ++++++++ Counting Sort/Tests/Tests.xcodeproj/project.pbxproj | 5 +++-- .../xcshareddata/IDEWorkspaceChecks.plist | 8 ++++++++ 3 files changed, 19 insertions(+), 2 deletions(-) create mode 100644 Counting Sort/CountingSort.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist create mode 100644 Counting Sort/Tests/Tests.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist diff --git a/Counting Sort/CountingSort.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Counting Sort/CountingSort.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/Counting Sort/CountingSort.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/Counting Sort/Tests/Tests.xcodeproj/project.pbxproj b/Counting Sort/Tests/Tests.xcodeproj/project.pbxproj index 5cbb0d4aa..aaa6c1b6b 100644 --- a/Counting Sort/Tests/Tests.xcodeproj/project.pbxproj +++ b/Counting Sort/Tests/Tests.xcodeproj/project.pbxproj @@ -97,6 +97,7 @@ developmentRegion = English; hasScannedForEncodings = 0; knownRegions = ( + English, en, Base, ); @@ -226,7 +227,7 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = swift.algorithm.club.Tests; PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 3.0; + SWIFT_VERSION = 5.0; }; name = Debug; }; @@ -238,7 +239,7 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = swift.algorithm.club.Tests; PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 3.0; + SWIFT_VERSION = 5.0; }; name = Release; }; diff --git a/Counting Sort/Tests/Tests.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Counting Sort/Tests/Tests.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/Counting Sort/Tests/Tests.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + From bf38b12ddc30c6e396a50e61e3dc342ced28e538 Mon Sep 17 00:00:00 2001 From: Jagdeep Matharu Date: Sun, 31 May 2020 19:58:21 -0400 Subject: [PATCH 250/271] Minor change in comment --- Counting Sort/CountingSort.playground/Contents.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Counting Sort/CountingSort.playground/Contents.swift b/Counting Sort/CountingSort.playground/Contents.swift index 839b16bc8..99178f85d 100644 --- a/Counting Sort/CountingSort.playground/Contents.swift +++ b/Counting Sort/CountingSort.playground/Contents.swift @@ -30,7 +30,7 @@ func countingSort(array: [Int]) throws -> [Int] { // Step 3 // Place the element in the final array as per the number of elements before it // Loop through the array in reverse to keep the stability of the new array - // (i.e. 7, is at index 3 and 6, thus in sortedArray the position of 7 at index 3 should be before 7 at index 6 + // i.e. 7, is at index 3 and 6, thus in sortedArray the position of 7 at index 3 should be before 7 at index 6 var sortedArray = [Int](repeating: 0, count: array.count) for index in stride(from: array.count - 1, through: 0, by: -1) { let element = array[index] From d8d165208465c8c725eda950e8cb2ddb3d7cfdca Mon Sep 17 00:00:00 2001 From: Yossa Bourne Date: Thu, 11 Jun 2020 09:56:40 +0700 Subject: [PATCH 251/271] Fix Swift (language) typos --- Introsort/README.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Introsort/README.markdown b/Introsort/README.markdown index 376703cf7..3e596ee89 100644 --- a/Introsort/README.markdown +++ b/Introsort/README.markdown @@ -2,7 +2,7 @@ Goal: Sort an array from low to high (or high to low). -IntroSort is the algorithm used by swift to sort a collection. Introsort is an hybrid algorithm invented by David Musser in 1993 with the purpose of giving a generic sorting algorithm for the C++ standard library. The classic implementation of introsort expect a recursive Quicksort with fallback to Heapsort in case the recursion depth level reached a certain max. The maximum depends on the number of elements in the collection and it is usually 2 * log(n). The reason behind this “fallback” is that if Quicksort was not able to get the solution after 2 * log(n) recursions for a branch, probably it hit its worst case and it is degrading to complexity O( n^2 ). To optimise even further this algorithm, the swift implementation introduce an extra step in each recursion where the partition is sorted using InsertionSort if the count of the partition is less than 20. +IntroSort is the algorithm used by Swift to sort a collection. Introsort is an hybrid algorithm invented by David Musser in 1993 with the purpose of giving a generic sorting algorithm for the C++ standard library. The classic implementation of introsort expect a recursive Quicksort with fallback to Heapsort in case the recursion depth level reached a certain max. The maximum depends on the number of elements in the collection and it is usually 2 * log(n). The reason behind this “fallback” is that if Quicksort was not able to get the solution after 2 * log(n) recursions for a branch, probably it hit its worst case and it is degrading to complexity O( n^2 ). To optimise even further this algorithm, the Swift implementation introduce an extra step in each recursion where the partition is sorted using InsertionSort if the count of the partition is less than 20. The number 20 is an empiric number obtained observing the behaviour of InsertionSort with lists of this size. From 9bc6aad9aaa56ce53ea7319f52c25585651e737a Mon Sep 17 00:00:00 2001 From: Roberto Efrain Hernandez Date: Wed, 10 Jun 2020 23:44:40 -0700 Subject: [PATCH 252/271] Updating how String can be casted into an Array. Just wanted to update the syntax from Array(self.characters) to Array(self). Similarly for casting of the ptnr String. --- Knuth-Morris-Pratt/KnuthMorrisPratt.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Knuth-Morris-Pratt/KnuthMorrisPratt.swift b/Knuth-Morris-Pratt/KnuthMorrisPratt.swift index 81bc65278..be0cd961d 100644 --- a/Knuth-Morris-Pratt/KnuthMorrisPratt.swift +++ b/Knuth-Morris-Pratt/KnuthMorrisPratt.swift @@ -12,8 +12,8 @@ extension String { func indexesOf(ptnr: String) -> [Int]? { - let text = Array(self.characters) - let pattern = Array(ptnr.characters) + let text = Array(self) + let pattern = Array(ptnr) let textLength: Int = text.count let patternLength: Int = pattern.count From abfa66b02d35b6320a5e404241db94d4317386d6 Mon Sep 17 00:00:00 2001 From: msalvacion Date: Thu, 11 Jun 2020 15:32:05 -0700 Subject: [PATCH 253/271] Fix: Typos in Heap README.markdown Added missing word and fixed a typo --- Heap/README.markdown | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Heap/README.markdown b/Heap/README.markdown index 6c65fe9c8..fee881129 100755 --- a/Heap/README.markdown +++ b/Heap/README.markdown @@ -82,7 +82,7 @@ array[parent(i)] >= array[i] Verify that this heap property holds for the array from the example heap. -As you can see, these equations allow us to find the parent or child index for any node without the need for pointers. It is complicated than just dereferencing a pointer, but that is the tradeoff: we save memory space but pay with extra computations. Fortunately, the computations are fast and only take **O(1)** time. +As you can see, these equations allow us to find the parent or child index for any node without the need for pointers. It is more complicated than just dereferencing a pointer, but that is the tradeoff: we save memory space but pay with extra computations. Fortunately, the computations are fast and only take **O(1)** time. It is important to understand this relationship between array index and position in the tree. Here is a larger heap which has 15 nodes divided over four levels: @@ -164,7 +164,7 @@ All of the above take time **O(log n)** because shifting up or down is expensive - `buildHeap(array)`: Converts an (unsorted) array into a heap by repeatedly calling `insert()`. If you are smart about this, it can be done in **O(n)** time. -- [Heap sort](../Heap%20Sort/). Since the heap is an array, we can use its unique properties to sort the array from low to high. Time: **O(n lg n).** +- [Heap sort](../Heap%20Sort/). Since the heap is an array, we can use its unique properties to sort the array from low to high. Time: **O(n log n).** The heap also has a `peek()` function that returns the maximum (max-heap) or minimum (min-heap) element, without removing it from the heap. Time: **O(1)**. From f30e53c3cb45af31f8b80c35a8c4ee781d1ee311 Mon Sep 17 00:00:00 2001 From: Kelvin Lau Date: Mon, 15 Jun 2020 18:23:10 -0400 Subject: [PATCH 254/271] Fixes a few typos --- Introsort/README.markdown | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Introsort/README.markdown b/Introsort/README.markdown index 3e596ee89..280950928 100644 --- a/Introsort/README.markdown +++ b/Introsort/README.markdown @@ -2,7 +2,9 @@ Goal: Sort an array from low to high (or high to low). -IntroSort is the algorithm used by Swift to sort a collection. Introsort is an hybrid algorithm invented by David Musser in 1993 with the purpose of giving a generic sorting algorithm for the C++ standard library. The classic implementation of introsort expect a recursive Quicksort with fallback to Heapsort in case the recursion depth level reached a certain max. The maximum depends on the number of elements in the collection and it is usually 2 * log(n). The reason behind this “fallback” is that if Quicksort was not able to get the solution after 2 * log(n) recursions for a branch, probably it hit its worst case and it is degrading to complexity O( n^2 ). To optimise even further this algorithm, the Swift implementation introduce an extra step in each recursion where the partition is sorted using InsertionSort if the count of the partition is less than 20. +IntroSort is the algorithm used by Swift to sort a collection. Introsort is an hybrid algorithm invented by David Musser in 1993 with the purpose of giving a generic sorting algorithm for the C++ standard library. + +The classic implementation of introsort uses a recursive Quicksort with a fallback to Heapsort in the case where the recursion depth level reached a certain maximum value. The maximum depends on the number of elements in the collection and it is usually 2 * log(n). The reason behind this “fallback” is that if Quicksort was not able to get the solution after 2 * log(n) recursions for a branch, probably it hit its worst case and it is degrading to complexity O( n^2 ). To optimise even further this algorithm, the Swift implementation introduce an extra step in each recursion where the partition is sorted using InsertionSort if the count of the partition is less than 20. The number 20 is an empiric number obtained observing the behaviour of InsertionSort with lists of this size. From f4fb2fc0eb04ab6a7862ae903f258741896f9ec1 Mon Sep 17 00:00:00 2001 From: nghiahoang Date: Thu, 25 Jun 2020 13:17:01 +0700 Subject: [PATCH 255/271] fix: SplayTree.remove is broken --- .../SplayTree.playground/Contents.swift | 33 +---- .../Sources/SplayTree.swift | 122 ++++------------- Splay Tree/SplayTree.swift | 124 ++++-------------- Splay Tree/readme.md | 7 +- 4 files changed, 57 insertions(+), 229 deletions(-) diff --git a/Splay Tree/SplayTree.playground/Contents.swift b/Splay Tree/SplayTree.playground/Contents.swift index a8a0bc5c6..28a201b37 100644 --- a/Splay Tree/SplayTree.playground/Contents.swift +++ b/Splay Tree/SplayTree.playground/Contents.swift @@ -5,29 +5,10 @@ print("Hello, Swift 4!") #endif -let splayTree = SplayTree(value: 1) -splayTree.insert(value: 2) -splayTree.insert(value: 10) -splayTree.insert(value: 6) - -splayTree.remove(value: 10) -splayTree.remove(value: 6) - -splayTree.insert(value: 55) -splayTree.insert(value: 559) -splayTree.remove(value: 2) -splayTree.remove(value: 1) -splayTree.remove(value: 55) -splayTree.remove(value: 559) - -splayTree.insert(value: 1843000) -splayTree.insert(value: 1238) -splayTree.insert(value: -1) -splayTree.insert(value: 87) - -splayTree.minimum() -splayTree.maximum() - - - - +var tree = SplayTree(value: 0) +tree.insert(value: 2) +tree.insert(value: 3) +tree.insert(value: 4) +tree.insert(value: 7) +_ = tree.search(value: 2) +tree.remove(value: 2) diff --git a/Splay Tree/SplayTree.playground/Sources/SplayTree.swift b/Splay Tree/SplayTree.playground/Sources/SplayTree.swift index 9e484129c..f450eaced 100644 --- a/Splay Tree/SplayTree.playground/Sources/SplayTree.swift +++ b/Splay Tree/SplayTree.playground/Sources/SplayTree.swift @@ -289,120 +289,42 @@ extension Node { - Node Resulting from the deletion and the splaying of the removed node */ - public func remove(value: T) -> Node? { - let replacement: Node? + fileprivate func remove(value: T) -> Node? { + guard let target = search(value: value) else { return self } - if let v = self.value, v == value { + if let left = target.left, let right = target.right { + let largestOfLeftChild = left.maximum() + left.parent = nil + right.parent = nil - var parentToSplay: Node? - if let left = left { - if let right = right { - - replacement = removeNodeWithTwoChildren(left, right) - - if let replacement = replacement, - let replacementParent = replacement.parent, - replacementParent.value != self.value { - - parentToSplay = replacement.parent - - } else if self.parent != nil { - parentToSplay = self.parent - } else { - parentToSplay = replacement - } - - } else { - // This node only has a left child. The left child replaces the node. - replacement = left - if self.parent != nil { - parentToSplay = self.parent - } else { - parentToSplay = replacement - } - } - } else if let right = right { - // This node only has a right child. The right child replaces the node. - replacement = right - if self.parent != nil { - parentToSplay = self.parent - } else { - parentToSplay = replacement - } - } else { - // This node has no children. We just disconnect it from its parent. - replacement = nil - parentToSplay = parent - } - - reconnectParentTo(node: replacement) + SplayOperation.splay(node: largestOfLeftChild) + largestOfLeftChild.right = right - // performs the splay operation - if let parentToSplay = parentToSplay { - SplayOperation.splay(node: parentToSplay) - } + return largestOfLeftChild - // The current node is no longer part of the tree, so clean it up. - parent = nil - left = nil - right = nil + } else if let left = target.left { + replace(node: target, with: left) + return left - return parentToSplay + } else if let right = target.right { + replace(node: target, with: right) + return right - } else if let v = self.value, value < v { - if left != nil { - return left!.remove(value: value) - } else { - let node = self - SplayOperation.splay(node: node) - return node - - } } else { - if right != nil { - return right?.remove(value: value) - } else { - let node = self - SplayOperation.splay(node: node) - return node - - } + return nil } } - private func removeNodeWithTwoChildren(_ left: Node, _ right: Node) -> Node { - // This node has two children. It must be replaced by the smallest - // child that is larger than this node's value, which is the leftmost - // descendent of the right child. - let successor = right.minimum() + private func replace(node: Node, with newNode: Node?) { + guard let sourceParent = sourceNode.parent else { return } - // Connect our left child with the new node. - successor.left = left - left.parent = successor - - // Connect our right child with the new node. If the right child does - // not have any left children of its own, then the in-order successor - // *is* the right child. - if right !== successor { - successor.right = right - right.parent = successor + if sourceNode.isLeftChild { + sourceParent.left = newNode } else { - successor.right = nil + sourceParent.right = newNode } - // And finally, connect the successor node to our parent. - return successor - } - - private func reconnectParentTo(node: Node?) { - if let parent = parent { - if isLeftChild { - parent.left = node - } else { - parent.right = node - } - } - node?.parent = parent + newNode?.parent = sourceParent } } diff --git a/Splay Tree/SplayTree.swift b/Splay Tree/SplayTree.swift index a7b20743d..0f1fa48f0 100644 --- a/Splay Tree/SplayTree.swift +++ b/Splay Tree/SplayTree.swift @@ -44,7 +44,7 @@ public enum SplayOperation { - Returns - Operation Case zigZag - zigZig - zig */ - public static func operation(forNode node: Node) -> SplayOperation { + public static func operation(forNode node: Node) -> SplayOperation { if let parent = node.parent, let _ = parent.parent { if (node.isLeftChild && parent.isRightChild) || (node.isRightChild && parent.isLeftChild) { @@ -289,120 +289,42 @@ extension Node { - Node Resulting from the deletion and the splaying of the removed node */ - public func remove(value: T) -> Node? { - let replacement: Node? + fileprivate func remove(value: T) -> Node? { + guard let target = search(value: value) else { return self } - if let v = self.value, v == value { + if let left = target.left, let right = target.right { + let largestOfLeftChild = left.maximum() + left.parent = nil + right.parent = nil - var parentToSplay: Node? - if let left = left { - if let right = right { - - replacement = removeNodeWithTwoChildren(left, right) - - if let replacement = replacement, - let replacementParent = replacement.parent, - replacementParent.value != self.value { - - parentToSplay = replacement.parent - - } else if self.parent != nil { - parentToSplay = self.parent - } else { - parentToSplay = replacement - } - - } else { - // This node only has a left child. The left child replaces the node. - replacement = left - if self.parent != nil { - parentToSplay = self.parent - } else { - parentToSplay = replacement - } - } - } else if let right = right { - // This node only has a right child. The right child replaces the node. - replacement = right - if self.parent != nil { - parentToSplay = self.parent - } else { - parentToSplay = replacement - } - } else { - // This node has no children. We just disconnect it from its parent. - replacement = nil - parentToSplay = parent - } + SplayOperation.splay(node: largestOfLeftChild) + largestOfLeftChild.right = right - reconnectParentTo(node: replacement) + return largestOfLeftChild - // performs the splay operation - if let parentToSplay = parentToSplay { - SplayOperation.splay(node: parentToSplay) - } + } else if let left = target.left { + replace(node: target, with: left) + return left - // The current node is no longer part of the tree, so clean it up. - parent = nil - left = nil - right = nil - - return parentToSplay + } else if let right = target.right { + replace(node: target, with: right) + return right - } else if let v = self.value, value < v { - if left != nil { - return left!.remove(value: value) - } else { - let node = self - SplayOperation.splay(node: node) - return node - - } } else { - if right != nil { - return right?.remove(value: value) - } else { - let node = self - SplayOperation.splay(node: node) - return node - - } + return nil } } - private func removeNodeWithTwoChildren(_ left: Node, _ right: Node) -> Node { - // This node has two children. It must be replaced by the smallest - // child that is larger than this node's value, which is the leftmost - // descendent of the right child. - let successor = right.minimum() + private func replace(node: Node, with newNode: Node?) { + guard let sourceParent = sourceNode.parent else { return } - // Connect our left child with the new node. - successor.left = left - left.parent = successor - - // Connect our right child with the new node. If the right child does - // not have any left children of its own, then the in-order successor - // *is* the right child. - if right !== successor { - successor.right = right - right.parent = successor + if sourceNode.isLeftChild { + sourceParent.left = newNode } else { - successor.right = nil + sourceParent.right = newNode } - // And finally, connect the successor node to our parent. - return successor - } - - private func reconnectParentTo(node: Node?) { - if let parent = parent { - if isLeftChild { - parent.left = node - } else { - parent.right = node - } - } - node?.parent = parent + newNode?.parent = sourceParent } } diff --git a/Splay Tree/readme.md b/Splay Tree/readme.md index 75c3c0389..8a852c950 100644 --- a/Splay Tree/readme.md +++ b/Splay Tree/readme.md @@ -102,8 +102,11 @@ To insert a value: To delete a value: -- Delete it as in a binary search tree -- Splay the parent of the removed node to the root +- Perform search for the value, after performed search function if the tree contains the value, it'll be the root of the new tree. +- If the tree has only left child, change left child to the root of the tree, remove the old root node +- If the tree has only right child, change right child to the root of the tree, remove the old root node +- Else, the tree has both two children, set parent of two children to nil, so that they're two new trees (left-tree and right-tree). +- Splay the minimum node of right-tree (or minimum node of left-tree), then set left-tree as left child of new root of right-tree (or set right-tree as right child of new root of left-tree), return right-tree ### Search From 73f009209e99eaed53a6c81bf72dae83a5397cb4 Mon Sep 17 00:00:00 2001 From: Ahmed Abdulkareem Rezik Date: Thu, 9 Jul 2020 14:33:03 +0200 Subject: [PATCH 256/271] Fixed Hashable Conformance to hash(into:) --- Graph/Graph/Edge.swift | 14 +++++++------- Graph/Graph/Vertex.swift | 6 ++++-- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/Graph/Graph/Edge.swift b/Graph/Graph/Edge.swift index ac5ed6a25..61cb576d1 100644 --- a/Graph/Graph/Edge.swift +++ b/Graph/Graph/Edge.swift @@ -29,13 +29,13 @@ extension Edge: CustomStringConvertible { extension Edge: Hashable { - public var hashValue: Int { - var string = "\(from.description)\(to.description)" - if weight != nil { - string.append("\(weight!)") - } - return string.hashValue - } + public func hash(into hasher: inout Hasher) { + hasher.combine(from) + hasher.combine(to) + if weight != nil { + hasher.combine(weight) + } + } } public func == (lhs: Edge, rhs: Edge) -> Bool { diff --git a/Graph/Graph/Vertex.swift b/Graph/Graph/Vertex.swift index 758a367bb..cdf39ba62 100644 --- a/Graph/Graph/Vertex.swift +++ b/Graph/Graph/Vertex.swift @@ -24,8 +24,10 @@ extension Vertex: CustomStringConvertible { extension Vertex: Hashable { - public var hashValue: Int { - return "\(data)\(index)".hashValue + public func hasher(into hasher: inout Hasher){ + + hasher.combine(data) + hasher.combine(index) } } From 0513f7d1d0432d844357f5b931bfc5e0d1940870 Mon Sep 17 00:00:00 2001 From: Ahmed Abdulkareem Rezik Date: Thu, 9 Jul 2020 14:37:37 +0200 Subject: [PATCH 257/271] Fixed Conformance to Hashable Protocol in Vertex and Edge structs --- Graph/Graph/Edge.swift | 14 ++++++++------ Graph/Graph/Vertex.swift | 12 +++++++----- 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/Graph/Graph/Edge.swift b/Graph/Graph/Edge.swift index 61cb576d1..1f29e07dd 100644 --- a/Graph/Graph/Edge.swift +++ b/Graph/Graph/Edge.swift @@ -29,13 +29,15 @@ extension Edge: CustomStringConvertible { extension Edge: Hashable { + public func hash(into hasher: inout Hasher) { - hasher.combine(from) - hasher.combine(to) - if weight != nil { - hasher.combine(weight) - } - } + hasher.combine(from) + hasher.combine(to) + if weight != nil { + hasher.combine(weight) + } + } + } public func == (lhs: Edge, rhs: Edge) -> Bool { diff --git a/Graph/Graph/Vertex.swift b/Graph/Graph/Vertex.swift index cdf39ba62..45b2c3088 100644 --- a/Graph/Graph/Vertex.swift +++ b/Graph/Graph/Vertex.swift @@ -24,11 +24,13 @@ extension Vertex: CustomStringConvertible { extension Vertex: Hashable { - public func hasher(into hasher: inout Hasher){ - - hasher.combine(data) - hasher.combine(index) - } + + + public func hasher(into hasher: inout Hasher){ + + hasher.combine(data) + hasher.combine(index) + } } From 4311cad2e332b9454c1189bddcbbca5f156a3d4c Mon Sep 17 00:00:00 2001 From: Samuel Huang Date: Wed, 22 Jul 2020 13:26:35 -0700 Subject: [PATCH 258/271] Update BTree.swift Fix spelling of swift markers - rename `Travelsals` to `Traversals` --- B-Tree/BTree.playground/Sources/BTree.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/B-Tree/BTree.playground/Sources/BTree.swift b/B-Tree/BTree.playground/Sources/BTree.swift index 2693eb308..2ed0b2593 100644 --- a/B-Tree/BTree.playground/Sources/BTree.swift +++ b/B-Tree/BTree.playground/Sources/BTree.swift @@ -86,7 +86,7 @@ extension BTreeNode { } } -// MARK: BTreeNode extension: Travelsals +// MARK: BTreeNode extension: Traversals extension BTreeNode { @@ -443,7 +443,7 @@ public class BTree { } } -// MARK: BTree extension: Travelsals +// MARK: BTree extension: Traversals extension BTree { /** From 617187bf4c36ab57948592d403e295cf8127d664 Mon Sep 17 00:00:00 2001 From: Richard Ash Date: Sat, 29 Aug 2020 13:37:23 -0700 Subject: [PATCH 259/271] Update style of Graph --- .../xcshareddata/IDEWorkspaceChecks.plist | 8 ++++++++ .../xcshareddata/IDEWorkspaceChecks.plist | 8 ++++++++ Graph/Graph/Edge.swift | 15 +++++++-------- 3 files changed, 23 insertions(+), 8 deletions(-) create mode 100644 Graph/Graph.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist create mode 100644 Graph/Graph.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist diff --git a/Graph/Graph.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Graph/Graph.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/Graph/Graph.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/Graph/Graph.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Graph/Graph.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/Graph/Graph.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/Graph/Graph/Edge.swift b/Graph/Graph/Edge.swift index 3c95f9666..9ddd4e23d 100644 --- a/Graph/Graph/Edge.swift +++ b/Graph/Graph/Edge.swift @@ -29,14 +29,13 @@ extension Edge: CustomStringConvertible { extension Edge: Hashable { - public func hash(into hasher: inout Hasher) { - hasher.combine(from) - hasher.combine(to) - if weight != nil { - hasher.combine(weight) - } - } - + public func hash(into hasher: inout Hasher) { + hasher.combine(from) + hasher.combine(to) + if weight != nil { + hasher.combine(weight) + } + } } From d951e67ec24167c9518bcab4e91946ce956978f3 Mon Sep 17 00:00:00 2001 From: Richard Ash Date: Sat, 29 Aug 2020 13:57:25 -0700 Subject: [PATCH 260/271] Update README.markdown --- README.markdown | 1 + 1 file changed, 1 insertion(+) diff --git a/README.markdown b/README.markdown index 3e0174576..093c5b9e7 100644 --- a/README.markdown +++ b/README.markdown @@ -195,6 +195,7 @@ Most of the time using just the built-in `Array`, `Dictionary`, and `Set` types - [Minimum Spanning Tree](Minimum%20Spanning%20Tree/) - [All-Pairs Shortest Paths](All-Pairs%20Shortest%20Paths/) - [Dijkstra's shortest path algorithm](Dijkstra%20Algorithm/) +- [A*](A-star/) ## Puzzles From 7bba2b28da53b3764f24c7fa455fe37065948530 Mon Sep 17 00:00:00 2001 From: Richard Ash Date: Sat, 29 Aug 2020 13:58:06 -0700 Subject: [PATCH 261/271] Update README.markdown --- README.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.markdown b/README.markdown index 093c5b9e7..b8b59bbcc 100644 --- a/README.markdown +++ b/README.markdown @@ -195,7 +195,7 @@ Most of the time using just the built-in `Array`, `Dictionary`, and `Set` types - [Minimum Spanning Tree](Minimum%20Spanning%20Tree/) - [All-Pairs Shortest Paths](All-Pairs%20Shortest%20Paths/) - [Dijkstra's shortest path algorithm](Dijkstra%20Algorithm/) -- [A*](A-star/) +- [A-star](A-star/) ## Puzzles From cf518c04b31013a4f1b468648967eb7a7a3694b6 Mon Sep 17 00:00:00 2001 From: Richard Ash Date: Sat, 29 Aug 2020 13:58:47 -0700 Subject: [PATCH 262/271] Update README.markdown --- README.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.markdown b/README.markdown index b8b59bbcc..e87fe0335 100644 --- a/README.markdown +++ b/README.markdown @@ -195,7 +195,7 @@ Most of the time using just the built-in `Array`, `Dictionary`, and `Set` types - [Minimum Spanning Tree](Minimum%20Spanning%20Tree/) - [All-Pairs Shortest Paths](All-Pairs%20Shortest%20Paths/) - [Dijkstra's shortest path algorithm](Dijkstra%20Algorithm/) -- [A-star](A-star/) +- [A-Star](A-Star/) ## Puzzles From e515919e305371cbff38319e00d21c90b35188e4 Mon Sep 17 00:00:00 2001 From: Richard Ash Date: Sat, 29 Aug 2020 14:24:59 -0700 Subject: [PATCH 263/271] Update Vertex.swift --- Graph/Graph/Vertex.swift | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/Graph/Graph/Vertex.swift b/Graph/Graph/Vertex.swift index f74b38396..48645f0fa 100644 --- a/Graph/Graph/Vertex.swift +++ b/Graph/Graph/Vertex.swift @@ -24,16 +24,10 @@ extension Vertex: CustomStringConvertible { extension Vertex: Hashable { - - - - public func hasher(into hasher: inout Hasher){ - - hasher.combine(data) - hasher.combine(index) - } - - + public func hasher(into hasher: inout Hasher) { + hasher.combine(data) + hasher.combine(index) + } } From 81e2726f03ea14a5f92ddafe2e093cba9bee84c1 Mon Sep 17 00:00:00 2001 From: Richard Ash Date: Sat, 29 Aug 2020 14:35:34 -0700 Subject: [PATCH 264/271] Update Linked List/README.markdown --- Linked List/README.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Linked List/README.markdown b/Linked List/README.markdown index d6f1fc986..c80b11d6f 100644 --- a/Linked List/README.markdown +++ b/Linked List/README.markdown @@ -491,7 +491,7 @@ Recursive Approach: } let temp = reverse(head.next) head.next.next = head - head.next = NULL + head.next = nil return temp } ``` From 15229cf1b57bd5bd95e81a19a0fd7de9abe0bb6f Mon Sep 17 00:00:00 2001 From: Richard Ash Date: Sat, 29 Aug 2020 14:38:06 -0700 Subject: [PATCH 265/271] Update Linked List/README.markdown --- Linked List/README.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Linked List/README.markdown b/Linked List/README.markdown index c80b11d6f..fdbc2ee84 100644 --- a/Linked List/README.markdown +++ b/Linked List/README.markdown @@ -486,7 +486,7 @@ Iterative Approach: Recursive Approach: ```swift public func reverse(node: head) { - if (!head || !(head.next)) { + if !head || !head.next { return head } let temp = reverse(head.next) From d664df8cb4fea0aad54d2e693f01684cec0590f9 Mon Sep 17 00:00:00 2001 From: Hashem Date: Mon, 29 Mar 2021 15:58:37 +0400 Subject: [PATCH 266/271] Update README.markdown `sort()` is in place sort. in reveres `sorted()` returns a sorted copy of the original array --- Insertion Sort/README.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Insertion Sort/README.markdown b/Insertion Sort/README.markdown index 8c2a5c1a0..1c41aa91d 100644 --- a/Insertion Sort/README.markdown +++ b/Insertion Sort/README.markdown @@ -114,7 +114,7 @@ insertionSort(list) Here is how the code works. -1. Make a copy of the array. This is necessary because we cannot modify the contents of the `array` parameter directly. Like Swift's own `sort()`, the `insertionSort()` function will return a sorted *copy* of the original array. +1. Make a copy of the array. This is necessary because we cannot modify the contents of the `array` parameter directly. Like Swift's own `sorted()`, the `insertionSort()` function will return a sorted *copy* of the original array. 2. There are two loops inside this function. The outer loop looks at each of the elements in the array in turn; this is what picks the top-most number from the pile. The variable `x` is the index of where the sorted portion ends and the pile begins (the position of the `|` bar). Remember, at any given moment the beginning of the array -- from index 0 up to `x` -- is always sorted. The rest, from index `x` until the last element, is the unsorted pile. From 90e23a6790f1f0a0e3704314a08be02114bcdf11 Mon Sep 17 00:00:00 2001 From: Coskun Deniz Date: Sat, 21 Aug 2021 19:44:58 +0100 Subject: [PATCH 267/271] declare 'index' as variable --- Insertion Sort/InsertionSort.swift | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/Insertion Sort/InsertionSort.swift b/Insertion Sort/InsertionSort.swift index e24ede905..5f0b6c2b4 100644 --- a/Insertion Sort/InsertionSort.swift +++ b/Insertion Sort/InsertionSort.swift @@ -28,14 +28,13 @@ func insertionSort(_ array: [T]) -> [T] { guard array.count > 1 else { return array } var sortedArray = array - for index in 1.. 0, temp < sortedArray[currentIndex - 1] { - sortedArray[currentIndex] = sortedArray[currentIndex - 1] - currentIndex -= 1 + for var index in 1.. 0, temp < sortedArray[index - 1] { + sortedArray[index] = sortedArray[index - 1] + index -= 1 } - sortedArray[currentIndex] = temp + sortedArray[index] = temp } return sortedArray } From 5ad2c68e359c6676df6b3b95315fe8d2b8d70d81 Mon Sep 17 00:00:00 2001 From: Aaron Watkins Date: Fri, 26 Nov 2021 16:35:21 -0500 Subject: [PATCH 268/271] legacy variables names correct legacy variable name `x` to be `index` so reader isnt wasting time scratching their head and can focus more on understanding the insertion sort algorithm. --- Insertion Sort/README.markdown | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Insertion Sort/README.markdown b/Insertion Sort/README.markdown index 1c41aa91d..f37bfeaef 100644 --- a/Insertion Sort/README.markdown +++ b/Insertion Sort/README.markdown @@ -116,9 +116,9 @@ Here is how the code works. 1. Make a copy of the array. This is necessary because we cannot modify the contents of the `array` parameter directly. Like Swift's own `sorted()`, the `insertionSort()` function will return a sorted *copy* of the original array. -2. There are two loops inside this function. The outer loop looks at each of the elements in the array in turn; this is what picks the top-most number from the pile. The variable `x` is the index of where the sorted portion ends and the pile begins (the position of the `|` bar). Remember, at any given moment the beginning of the array -- from index 0 up to `x` -- is always sorted. The rest, from index `x` until the last element, is the unsorted pile. +2. There are two loops inside this function. The outer loop looks at each of the elements in the array in turn; this is what picks the top-most number from the pile. The variable `index` is the index of where the sorted portion ends and the pile begins (the position of the `|` bar). Remember, at any given moment the beginning of the array -- from index 0 up to `index` -- is always sorted. The rest, from index `index` until the last element, is the unsorted pile. -3. The inner loop looks at the element at position `x`. This is the number at the top of the pile, and it may be smaller than any of the previous elements. The inner loop steps backwards through the sorted array; every time it finds a previous number that is larger, it swaps them. When the inner loop completes, the beginning of the array is sorted again, and the sorted portion has grown by one element. +3. The inner loop looks at the element at position `index`. This is the number at the top of the pile, and it may be smaller than any of the previous elements. The inner loop steps backwards through the sorted array; every time it finds a previous number that is larger, it swaps them. When the inner loop completes, the beginning of the array is sorted again, and the sorted portion has grown by one element. > **Note:** The outer loop starts at index 1, not 0. Moving the very first element from the pile to the sorted portion doesn't actually change anything, so we might as well skip it. From eb4e151b55ff846c28be5d2357b7ab2f776a9dce Mon Sep 17 00:00:00 2001 From: Aaron Watkins Date: Fri, 26 Nov 2021 16:45:21 -0500 Subject: [PATCH 269/271] correct index to currentIndex --- Insertion Sort/README.markdown | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Insertion Sort/README.markdown b/Insertion Sort/README.markdown index f37bfeaef..f7b933b92 100644 --- a/Insertion Sort/README.markdown +++ b/Insertion Sort/README.markdown @@ -116,9 +116,9 @@ Here is how the code works. 1. Make a copy of the array. This is necessary because we cannot modify the contents of the `array` parameter directly. Like Swift's own `sorted()`, the `insertionSort()` function will return a sorted *copy* of the original array. -2. There are two loops inside this function. The outer loop looks at each of the elements in the array in turn; this is what picks the top-most number from the pile. The variable `index` is the index of where the sorted portion ends and the pile begins (the position of the `|` bar). Remember, at any given moment the beginning of the array -- from index 0 up to `index` -- is always sorted. The rest, from index `index` until the last element, is the unsorted pile. +2. There are two loops inside this function. The outer loop looks at each of the elements in the array in turn; this is what picks the top-most number from the pile. The variable `currentIndex` is the index of where the sorted portion ends and the pile begins (the position of the `|` bar). Remember, at any given moment the beginning of the array -- from index 0 up to `currentIndex` -- is always sorted. The rest, from index `currentIndex` until the last element, is the unsorted pile. -3. The inner loop looks at the element at position `index`. This is the number at the top of the pile, and it may be smaller than any of the previous elements. The inner loop steps backwards through the sorted array; every time it finds a previous number that is larger, it swaps them. When the inner loop completes, the beginning of the array is sorted again, and the sorted portion has grown by one element. +3. The inner loop looks at the element at position `currentIndex`. This is the number at the top of the pile, and it may be smaller than any of the previous elements. The inner loop steps backwards through the sorted array; every time it finds a previous number that is larger, it swaps them. When the inner loop completes, the beginning of the array is sorted again, and the sorted portion has grown by one element. > **Note:** The outer loop starts at index 1, not 0. Moving the very first element from the pile to the sorted portion doesn't actually change anything, so we might as well skip it. From 6af57a839d59db84ded9e95315d4a9aeff8a9d64 Mon Sep 17 00:00:00 2001 From: Namratha2604 Date: Thu, 26 Sep 2024 14:25:05 +0530 Subject: [PATCH 270/271] #986-corrected the comment --- Bloom Filter/BloomFilter.playground/Contents.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Bloom Filter/BloomFilter.playground/Contents.swift b/Bloom Filter/BloomFilter.playground/Contents.swift index 7a3719d57..8ed808a06 100644 --- a/Bloom Filter/BloomFilter.playground/Contents.swift +++ b/Bloom Filter/BloomFilter.playground/Contents.swift @@ -79,4 +79,4 @@ bloom.insert("Bloom Filterz") print(bloom.array) bloom.query("Bloom Filterz") // true -bloom.query("Hello WORLD") // true +bloom.query("Hello WORLD") // false or true: It may return true due to a false positive, but it's not guaranteed. From 5e8c02913c04d86d3b41ebf47210b9f974ad7d26 Mon Sep 17 00:00:00 2001 From: Nitesh J Date: Mon, 7 Oct 2024 14:05:17 +0530 Subject: [PATCH 271/271] issue resolved #997 and #998 Correction of the README.markdown and Selection Sampling code improvement #998 --- Selection Sampling/README.markdown | 2 +- Selection Sampling/SelectionSampling.swift | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Selection Sampling/README.markdown b/Selection Sampling/README.markdown index 741f592f4..5c2ff5e25 100644 --- a/Selection Sampling/README.markdown +++ b/Selection Sampling/README.markdown @@ -12,7 +12,7 @@ func select(from a: [T], count k: Int) -> [T] { for i in 0..(from a: [T], count k: Int) -> [T] { for i in 0..

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 literal 0 HcmV?d00001 diff --git a/swift-algorithm-club.xcworkspace/contents.xcworkspacedata b/swift-algorithm-club.xcworkspace/contents.xcworkspacedata index 5b8dd996f..ea6bdfa32 100644 --- a/swift-algorithm-club.xcworkspace/contents.xcworkspacedata +++ b/swift-algorithm-club.xcworkspace/contents.xcworkspacedata @@ -54,6 +54,13 @@ + + + + From be679572a9403d8c4c6fb8219b9f08dbda4f0f8c Mon Sep 17 00:00:00 2001 From: horita-yuya Date: Wed, 28 Feb 2018 01:14:33 +0900 Subject: [PATCH 014/271] :pencil: README --- Myers Difference Algorithm/README.md | 145 ++++++++++++++++++ .../contents.xcworkspacedata | 3 + 2 files changed, 148 insertions(+) diff --git a/Myers Difference Algorithm/README.md b/Myers Difference Algorithm/README.md index def447593..4e48a704f 100644 --- a/Myers Difference Algorithm/README.md +++ b/Myers Difference Algorithm/README.md @@ -1,2 +1,147 @@ # Myers Difference Algorithm +Myers Difference Algorithm is the algorithm to find a longest common subsequence or shortest edit scripts (LCS/SES dual probrem) of two sequences by a simple O(ND) time, where N is the sum of the lengths of the two sequences. Common subsequence is the sequence of elements that appear in the same order in both sequences. Edit script will be discussed below. + +For example, assuming that sequence `A = ["1", "2", "3"]` and sequence `B = ["2", "3", "4"]`, `["2"], ["2", "3"]` are common sequences. Furthermore, the latter `["2", "3"]` is the longest common subsequence. But `["1", "2"], ["3", "2"]` are not. Because, `["1", "2"]` contains `"1"` that is not included in `B`, `["3", 2]` has elements are included in both, but the appearing order is not correct. + +## Finding the length of the Longest Common Subsequence with Myers Algorithm on Edit Graph + +### Edit Graph + +Myers Algorithm uses Edit Graph for solving LCS/SES problem. Edit Graph is the graph like below. + + + +Here, we think about the length of the LCS of sequences `X = [A, B, C, A, B, B, A]`, `Y = [C, B, A, B, A, C]`. + +In Myers Algorithm, edit graph are prepared by + +1. Line the element of sequence `X` on the x axis. And do for `Y` on the y axis. +2. Make grid and vertex at each point in the grid (x, y), `x in [0, N] and y in [0, M]`. `N` is the length of sequence `X`, `M` is of `Y` +3. Line for `x - y = k`, this line called k-line. Pink line is this. +3. Check the points `(i, j)`, where `X[i] = Y[j]`, called match point. +4. Connect vertex `(i - 1, j - 1)` and vertex `(i, j)`, then diagonal edge appears. + +> **Note:** Here, the sequences' start index is 1 not 0, so `X[1] = A`, `Y[1] = C` + +We discuss about which path is the shortest from `source` to `sink`. Can move on the edges on the graph. I mean we can move on the grid, horizontal and vertical edges, and the diagonal edges. + +The movements are compatible with the `Edit Scripts`, insert or delete. The word `Edit Scripts` appeared here, as referred at Introduction SES is Shortest Edit Scripts. + +Let's get back on track. On this edit graph, the horizontal movement to vertex `(i, j)` is compatible with the script `delete at index i from X`, the vertical movement to vertex `(i, j)` is compatible with the script `insert the element of Y at index j to immediately after the element of X at index i`. How about for the diagonal movement?. This movement to vertex `(i, j)` means `X[i] = Y[j]`, so no script needs. + +- horizontal movement -> delete +- vertical movement -> insert +- diagonal movement -> no script because both are same. + +Next, add cost 1 for non-diagonal movement, because they can be compatible with script. And 0 for diagonal movement, same means no script. + +The total cost for the minimum path, exploring from `source` to `sink`, is the same as the length of the Longest Common Subsequence or Shortest Edit Script. + +So, LSC/SES problem can be solved by finding the shortest path from `source` to `sink`. + +### Myers Algorithm + +As mentioned above, the problem of finding a shortest edit script can be reduced to finding a path from `source (0, 0)` to `sink (N, M)` with the fewest number of horizontal and vertical edges. Let `D-path` be a path starting at `source` that has exactly `D` non-diagonal edges, or must move non-diagonally D-times. + +For example, A 0-path consists solely of diagonal edges. This means both sequences are completely same. + +By a simple induction, D-path must consist of a (D-1)-path followed by a non-diagonal edge and then diagonal edges, which called `snake`. The minimum value of D is 0, both sequences being same. To the contrary, the maximum value of D is N + M because delete all elements from X and insert all elements from Y to X is the worst case edit scripts. For getting D, or the length of SES, running loop from 0 to N + M is enough. + +```swift +for D in 0...N + M +``` + +Next, thinking about, where is the furthest reaching point for D-path on k-line. Like below, moving horizontally from k-line reaches (k+1)-line, moving vertically from k-line reaches (k-1)-line. + + + +So, threre are several end points of D-path, or D-path can end on several k-line. We need the information to get the next path ((D+1)-path) as mentioned above. In fact, D-path must end on +k-line, where k in { -D, -D + 2, ....., D - 2, D }. This is so simple, starting point, `source` is `(0, 0)` on (k=0)-line. D is the number of non-diagonal edges and non-diagonal movement changes current k-line to (kpm1)-line. Because 0 is even number, if D is even number D-path will end on (even_k)-line, if D is odd number D-path will end on (odd_k)-line. + +Searching loop outline will be below. + +```swift +for D in 0...N + M { + for k in stride(from: -D, through: D, by: 2) { + //Find the end point of the furthest reaching D-path in k-line. + if furthestReachingX == N && furthestReachingY == M { + // The D-path is the shortest path + // D is the length of Shortest Edit Script + return + } + } +} +``` + +The D-path on k-line can be decomposed into +- a furthest reaching (D-1)-path on (k-1)-line, followed by a horizontal edge, followed by `snake`. +- a furthest reaching (D-1)-path on (k+1)-line, followed by a vertical edge, followed by `snake`. +as discussed above. + +The Myers Algorithm key point are these. +- D-path must end on k-line, where k in { -D, -D + 2, ....., D - 2, D } +- The D-path on k-line can be decomposed into two patterns + +thanks for these, the number of calculation become less. + +```swift +public struct MyersDifferenceAlgorithm { + public static func calculateShortestEditDistance(from fromArray: Array, to toArray: Array) -> Int { + let fromCount = fromArray.count + let toCount = toArray.count + let totalCount = toCount + fromCount + var furthestReaching = Array(repeating: 0, count: 2 * totalCount + 1) + + let isReachedAtSink: (Int, Int) -> Bool = { x, y in + return x == fromCount && y == toCount + } + + let snake: (Int, Int, Int) -> Int = { x, D, k in + var _x = x + while _x < fromCount && _x - k < toCount && fromArray[_x] == toArray[_x - k] { + _x += 1 + } + return _x + } + + for D in 0...totalCount { + for k in stride(from: -D, through: D, by: 2) { + let index = k + totalCount + + // (x, D, k) => the x position on the k_line where the number of scripts is D + // scripts means insertion or deletion + var x = 0 + if D == 0 { } + // k == -D, D will be the boundary k_line + // when k == -D, moving right on the Edit Graph(is delete script) from k - 1_line where D - 1 is unavailable. + // when k == D, moving bottom on the Edit Graph(is insert script) from k + 1_line where D - 1 is unavailable. + // furthestReaching x position has higher calculating priority. (x, D - 1, k - 1), (x, D - 1, k + 1) + else if k == -D || k != D && furthestReaching[index - 1] < furthestReaching[index + 1] { + // Getting initial x position + // ,using the furthestReaching X position on the k + 1_line where D - 1 + // ,meaning get (x, D, k) by (x, D - 1, k + 1) + moving bottom + snake + // this moving bottom on the edit graph is compatible with insert script + x = furthestReaching[index + 1] + } else { + // Getting initial x position + // ,using the futrhest X position on the k - 1_line where D - 1 + // ,meaning get (x, D, k) by (x, D - 1, k - 1) + moving right + snake + // this moving right on the edit graph is compatible with delete script + x = furthestReaching[index - 1] + 1 + } + + // snake + // diagonal moving can be performed with 0 cost. + // `same` script is needed ? + let _x = snake(x, D, k) + + if isReachedAtSink(_x, _x - k) { return D } + furthestReaching[index] = _x + } + } + + fatalError("Never comes here") + } +} +``` diff --git a/swift-algorithm-club.xcworkspace/contents.xcworkspacedata b/swift-algorithm-club.xcworkspace/contents.xcworkspacedata index ea6bdfa32..724755669 100644 --- a/swift-algorithm-club.xcworkspace/contents.xcworkspacedata +++ b/swift-algorithm-club.xcworkspace/contents.xcworkspacedata @@ -60,6 +60,9 @@ + + From b22d54af4185f54947cf143e2bf03359eb2263b8 Mon Sep 17 00:00:00 2001 From: horita-yuya Date: Wed, 28 Feb 2018 01:36:54 +0900 Subject: [PATCH 015/271] :hammer: fix typo and description --- Myers Difference Algorithm/README.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/Myers Difference Algorithm/README.md b/Myers Difference Algorithm/README.md index 4e48a704f..2f6c3c579 100644 --- a/Myers Difference Algorithm/README.md +++ b/Myers Difference Algorithm/README.md @@ -2,7 +2,7 @@ Myers Difference Algorithm is the algorithm to find a longest common subsequence or shortest edit scripts (LCS/SES dual probrem) of two sequences by a simple O(ND) time, where N is the sum of the lengths of the two sequences. Common subsequence is the sequence of elements that appear in the same order in both sequences. Edit script will be discussed below. -For example, assuming that sequence `A = ["1", "2", "3"]` and sequence `B = ["2", "3", "4"]`, `["2"], ["2", "3"]` are common sequences. Furthermore, the latter `["2", "3"]` is the longest common subsequence. But `["1", "2"], ["3", "2"]` are not. Because, `["1", "2"]` contains `"1"` that is not included in `B`, `["3", 2]` has elements are included in both, but the appearing order is not correct. +For example, assuming that sequence `A = ["1", "2", "3"]` and sequence `B = ["2", "3", "4"]`, `["2"], ["2", "3"]` are common sequences. Furthermore, the latter `["2", "3"]` is the longest common subsequence. But `["1", "2"], ["3", "2"]` are not. Because, `["1", "2"]` contains `"1"` that is not included in `B`, `["3", "2"]` has elements are included in both, but the appearing order is not correct. ## Finding the length of the Longest Common Subsequence with Myers Algorithm on Edit Graph @@ -10,7 +10,7 @@ For example, assuming that sequence `A = ["1", "2", "3"]` and sequence `B = ["2" Myers Algorithm uses Edit Graph for solving LCS/SES problem. Edit Graph is the graph like below. - + Here, we think about the length of the LCS of sequences `X = [A, B, C, A, B, B, A]`, `Y = [C, B, A, B, A, C]`. @@ -18,15 +18,15 @@ In Myers Algorithm, edit graph are prepared by 1. Line the element of sequence `X` on the x axis. And do for `Y` on the y axis. 2. Make grid and vertex at each point in the grid (x, y), `x in [0, N] and y in [0, M]`. `N` is the length of sequence `X`, `M` is of `Y` -3. Line for `x - y = k`, this line called k-line. Pink line is this. -3. Check the points `(i, j)`, where `X[i] = Y[j]`, called match point. -4. Connect vertex `(i - 1, j - 1)` and vertex `(i, j)`, then diagonal edge appears. +3. Line for `x - y = k`, this line called k-line. Black dot line is this and pink number is the value of k. +3. Check the points `(i, j)`, where `X[i] = Y[j]`, called match point, light green one. +4. Connect vertex `(i - 1, j - 1)` and vertex `(i, j)`, where `(i, j)` is match point, then diagonal edge appears. > **Note:** Here, the sequences' start index is 1 not 0, so `X[1] = A`, `Y[1] = C` We discuss about which path is the shortest from `source` to `sink`. Can move on the edges on the graph. I mean we can move on the grid, horizontal and vertical edges, and the diagonal edges. -The movements are compatible with the `Edit Scripts`, insert or delete. The word `Edit Scripts` appeared here, as referred at Introduction SES is Shortest Edit Scripts. +The movements are compatible with the `Edit Scripts`, insert or delete. The word `Edit Scripts` appeared here, as referred at Introduction, SES is Shortest Edit Scripts. Let's get back on track. On this edit graph, the horizontal movement to vertex `(i, j)` is compatible with the script `delete at index i from X`, the vertical movement to vertex `(i, j)` is compatible with the script `insert the element of Y at index j to immediately after the element of X at index i`. How about for the diagonal movement?. This movement to vertex `(i, j)` means `X[i] = Y[j]`, so no script needs. @@ -38,7 +38,7 @@ Next, add cost 1 for non-diagonal movement, because they can be compatible with The total cost for the minimum path, exploring from `source` to `sink`, is the same as the length of the Longest Common Subsequence or Shortest Edit Script. -So, LSC/SES problem can be solved by finding the shortest path from `source` to `sink`. +So, LCS/SES problem can be solved by finding the shortest path from `source` to `sink`. ### Myers Algorithm @@ -52,9 +52,9 @@ By a simple induction, D-path must consist of a (D-1)-path followed by a non-dia for D in 0...N + M ``` -Next, thinking about, where is the furthest reaching point for D-path on k-line. Like below, moving horizontally from k-line reaches (k+1)-line, moving vertically from k-line reaches (k-1)-line. +Next, thinking about, where is the furthest reaching point for D-path on k-line. Like below, moving horizontally from k-line reaches (k+1)-line, moving vertically from k-line reaches (k-1)-line. Red chalky line shows that. - + So, threre are several end points of D-path, or D-path can end on several k-line. We need the information to get the next path ((D+1)-path) as mentioned above. In fact, D-path must end on k-line, where k in { -D, -D + 2, ....., D - 2, D }. This is so simple, starting point, `source` is `(0, 0)` on (k=0)-line. D is the number of non-diagonal edges and non-diagonal movement changes current k-line to (kpm1)-line. Because 0 is even number, if D is even number D-path will end on (even_k)-line, if D is odd number D-path will end on (odd_k)-line. From 81befa64507475361183cd52d29b14ce65da2e03 Mon Sep 17 00:00:00 2001 From: Blaine Rothrock Date: Mon, 5 Mar 2018 09:22:32 -0600 Subject: [PATCH 016/271] tutorial; weighted choice --- Genetic/README.markdown | 49 +++++++- Genetic/gen.playground/Contents.swift | 52 +++++++++ Genetic/gen.swift | 154 +++++++++++--------------- 3 files changed, 167 insertions(+), 88 deletions(-) diff --git a/Genetic/README.markdown b/Genetic/README.markdown index 6ebbf2cf7..fdc6d5d92 100644 --- a/Genetic/README.markdown +++ b/Genetic/README.markdown @@ -188,4 +188,51 @@ The above is used to generate a completely new generation based on the current g ## Putting it all together -- Running the Genetic Algorithm -We now have all the methods we need to kick off the process. What is missing a `main()` function that loops though each generation of the GA. +We now have all the functions we need to kick off the algorthim. Let's start from the beginning, first we need a random population to serve as a starting point. We will also initialize a fittest variable to hold the fittest individual, we will initialize it with the first individual of our random population. + +```swift +var population:[[UInt8]] = randomPopulation(from: lex, populationSize: POP_SIZE, dnaSize: DNA_SIZE) +var fittest = population[0] +``` + +Now for the meat, the remainder of the code will take place in the generation loop, running once for every generation: + +```swift +for generation in 0...GENERATIONS { + // run +} +``` + +Now, for each individual in the population, we need to calculate its fitness and weighted value. For weighted choice we store the fitness as a percent `1 / fitness`. + +```swift +var weightedPopulation = [(item:[UInt8], weight:Double)]() + +for individual in population { + let fitnessValue = calculateFitness(dna: individual, optimal: OPTIMAL) + let pair = ( individual, fitnessValue == 0 ? 1.0 : 1.0/Double( fitnessValue ) ) + weightedPopulation.append(pair) +} +``` + +To understand weighted choice, let walk though a smaller example, let's say we have the following population, where 0 is the best fitness: + +```txt +1: 10 +2: 5 +3: 4 +4: 7 +5: 11 +``` + +Now here is the weight of each: + +```txt +1: +2: +3: +4: +5: + +total = +``` diff --git a/Genetic/gen.playground/Contents.swift b/Genetic/gen.playground/Contents.swift index 50d4c4fc8..4c67f8bd1 100644 --- a/Genetic/gen.playground/Contents.swift +++ b/Genetic/gen.playground/Contents.swift @@ -102,3 +102,55 @@ func crossover(dna1:[UInt8], dna2:[UInt8], dnaSize:Int) -> (dna1:[UInt8], dna2:[ [UInt8](dna2.prefix(upTo: dna2Index1) + dna1.suffix(from: dna1Index1)) ) } + +func main() { + + // generate the starting random population + var population:[[UInt8]] = randomPopulation(from: lex, populationSize: POP_SIZE, dnaSize: DNA_SIZE) + // print("population: \(population), dnaSize: \(DNA_SIZE) ") + var fittest = [UInt8]() + + for generation in 0...GENERATIONS { + print("Generation \(generation) with random sample: \(String(bytes: population[0], encoding:.ascii)!)") + + var weightedPopulation = [(item:[UInt8], weight:Double)]() + + // calulcated the fitness of each individual in the population + // and add it to the weight population (weighted = 1.0/fitness) + for individual in population { + let fitnessValue = calculateFitness(dna: individual, optimal: OPTIMAL) + + let pair = ( individual, fitnessValue == 0 ? 1.0 : 1.0/Double( fitnessValue ) ) + + weightedPopulation.append(pair) + } + + population = [] + + // create a new generation using the individuals in the origional population + for _ in 0...POP_SIZE/2 { + let ind1 = weightedChoice(items: weightedPopulation) + let ind2 = weightedChoice(items: weightedPopulation) + + let offspring = crossover(dna1: ind1.item, dna2: ind2.item, dnaSize: DNA_SIZE) + + // append to the population and mutate + population.append(mutate(lexicon: lex, dna: offspring.dna1, mutationChance: MUTATION_CHANCE)) + population.append(mutate(lexicon: lex, dna: offspring.dna2, mutationChance: MUTATION_CHANCE)) + } + + fittest = population[0] + var minFitness = calculateFitness(dna: fittest, optimal: OPTIMAL) + + // parse the population for the fittest string + for indv in population {lex + let indvFitness = calculateFitness(dna: indv, optimal: OPTIMAL) + if indvFitness < minFitness { + fittest = indv + minFitness = indvFitness + } + } + if minFitness == 0 { break; } + } + print("fittest string: \(String(bytes: fittest, encoding: .ascii)!)") +} diff --git a/Genetic/gen.swift b/Genetic/gen.swift index 17df6d002..f664fd5f7 100644 --- a/Genetic/gen.swift +++ b/Genetic/gen.swift @@ -1,46 +1,56 @@ -/* - base .. to be refactored -*/ +//: Playground - noun: a place where people can play import Foundation -// HELPERS -/* - String extension to convert a string to ascii value -*/ extension String { var asciiArray: [UInt8] { - return unicodeScalars.filter{$0.isASCII}.map{UInt8($0.value)} + return [UInt8](self.utf8) } } -let lex = " !\"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~".map { } -/* - helper function to return a random character string -*/ -func randomChar() -> UInt8 { +let lex: [UInt8] = " !\"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~".asciiArray - let letters : [UInt8] = " !\"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~".asciiArray - let len = UInt32(letters.count-1) +// This is the end goal and what we will be using to rate fitness. In the real world this will not exist +let OPTIMAL:[UInt8] = "Hello, World".asciiArray - let rand = Int(arc4random_uniform(len)) - return letters[rand] -} +// The length of the string in our population. Organisms need to be similar +let DNA_SIZE = OPTIMAL.count -// END HELPERS +// size of each generation +let POP_SIZE = 200 -let OPTIMAL:[UInt8] = "Hello, World".asciiArray -let DNA_SIZE = OPTIMAL.count -let POP_SIZE = 50 +// max number of generations, script will stop when it reach 5000 if the optimal value is not found let GENERATIONS = 5000 + +// The chance in which a random nucleotide can mutate (1/n) let MUTATION_CHANCE = 100 -/* - calculated the fitness based on approximate string matching - compares each character ascii value difference and adds that to a total fitness - optimal string comparsion = 0 -*/ +func randomChar(from lexicon: [UInt8]) -> UInt8 { + let len = UInt32(lexicon.count-1) + let rand = Int(arc4random_uniform(len)) + return lexicon[rand] +} + +func randomPopulation(from lexicon: [UInt8], populationSize: Int, dnaSize: Int) -> [[UInt8]] { + + let len = UInt32(lexicon.count) + + var pop = [[UInt8]]() + + for _ in 0.. Int { var fitness = 0 @@ -50,26 +60,37 @@ func calculateFitness(dna:[UInt8], optimal:[UInt8]) -> Int { return fitness } -/* - randomly mutate the string -*/ -func mutate(dna:[UInt8], mutationChance:Int, dnaSize:Int) -> [UInt8] { +calculateFitness(dna: "Gello, World".asciiArray, optimal: "Hello, World".asciiArray) + +func weightedChoice(items:[(item:[UInt8], weight:Double)]) -> (item:[UInt8], weight:Double) { + + let total = items.reduce(0.0) { return $0 + $1.weight} + + var n = Double(arc4random_uniform(UInt32(total * 1000000.0))) / 1000000.0 + + for itemTuple in items { + if n < itemTuple.weight { + return itemTuple + } + n = n - itemTuple.weight + } + return items[1] +} + +func mutate(lexicon: [UInt8], dna:[UInt8], mutationChance:Int) -> [UInt8] { var outputDna = dna - for i in 0.. (dna1:[UInt8], dna2:[UInt8]) { let pos = Int(arc4random_uniform(UInt32(dnaSize-1))) @@ -82,59 +103,15 @@ func crossover(dna1:[UInt8], dna2:[UInt8], dnaSize:Int) -> (dna1:[UInt8], dna2:[ ) } - -/* -returns a random population, used to start the evolution -*/ -func randomPopulation(populationSize: Int, dnaSize: Int) -> [[UInt8]] { - - let letters : [UInt8] = " !\"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~".asciiArray - let len = UInt32(letters.count) - - var pop = [[UInt8]]() - - for _ in 0.. (item:[UInt8], weight:Double) { - var weightTotal = 0.0 - for itemTuple in items { - weightTotal += itemTuple.weight; - } - - var n = Double(arc4random_uniform(UInt32(weightTotal * 1000000.0))) / 1000000.0 - - for itemTuple in items { - if n < itemTuple.weight { - return itemTuple - } - n = n - itemTuple.weight - } - return items[1] -} - func main() { // generate the starting random population - var population:[[UInt8]] = randomPopulation(populationSize: POP_SIZE, dnaSize: DNA_SIZE) + var population:[[UInt8]] = randomPopulation(from: lex, populationSize: POP_SIZE, dnaSize: DNA_SIZE) // print("population: \(population), dnaSize: \(DNA_SIZE) ") var fittest = [UInt8]() for generation in 0...GENERATIONS { - print("Generation \(generation) with random sample: \(String(bytes: population[0], encoding:.ascii)!)") + // print("Generation \(generation) with random sample: \(String(bytes: population[0], encoding:.ascii)!)") var weightedPopulation = [(item:[UInt8], weight:Double)]() @@ -143,7 +120,7 @@ func main() { for individual in population { let fitnessValue = calculateFitness(dna: individual, optimal: OPTIMAL) - let pair = ( individual, fitnessValue == 0 ? 1.0 : 1.0/Double( fitnessValue ) ) + let pair = ( individual, fitnessValue == 0 ? 1.0 : Double(100/POP_SIZE)/Double( fitnessValue ) ) weightedPopulation.append(pair) } @@ -158,15 +135,15 @@ func main() { let offspring = crossover(dna1: ind1.item, dna2: ind2.item, dnaSize: DNA_SIZE) // append to the population and mutate - population.append(mutate(dna: offspring.dna1, mutationChance: MUTATION_CHANCE, dnaSize: DNA_SIZE)) - population.append(mutate(dna: offspring.dna2, mutationChance: MUTATION_CHANCE, dnaSize: DNA_SIZE)) + population.append(mutate(lexicon: lex, dna: offspring.dna1, mutationChance: MUTATION_CHANCE)) + population.append(mutate(lexicon: lex, dna: offspring.dna2, mutationChance: MUTATION_CHANCE)) } fittest = population[0] var minFitness = calculateFitness(dna: fittest, optimal: OPTIMAL) // parse the population for the fittest string - for indv in population { + for indv in population {lex let indvFitness = calculateFitness(dna: indv, optimal: OPTIMAL) if indvFitness < minFitness { fittest = indv @@ -174,6 +151,9 @@ func main() { } } if minFitness == 0 { break; } + if generation % 1000 == 0 { + print("\(generation): \(String(bytes: fittest, encoding: .utf8)!)") + } } print("fittest string: \(String(bytes: fittest, encoding: .ascii)!)") } From 66f75d2c51b97f51259e8e6706433773e4a6e1af Mon Sep 17 00:00:00 2001 From: Blaine Rothrock Date: Fri, 9 Mar 2018 14:50:30 -0600 Subject: [PATCH 017/271] tutotial complete --- Genetic/README.markdown | 143 +++++++++++++++++++++----- Genetic/gen.playground/Contents.swift | 25 ++--- Genetic/gen.swift | 21 ++-- 3 files changed, 139 insertions(+), 50 deletions(-) diff --git a/Genetic/README.markdown b/Genetic/README.markdown index fdc6d5d92..92f121daa 100644 --- a/Genetic/README.markdown +++ b/Genetic/README.markdown @@ -1,4 +1,4 @@ -# Genetic Algorthim +individual# Genetic Algorthim ## What is it? @@ -20,7 +20,9 @@ The randomization that allows for organisms to change over time. In GAs we build Simply reproduction. A generation will a mixed representation of the previous generation, with offspring taking data (DNA) from both parents. GAs do this by randomly, but weightily, mating offspring to create new generations. ### Resources: -* [Wikipedia]() +* [Genetic Algorithms in Search Optimization, and Machine Learning](https://www.amazon.com/Genetic-Algorithms-Optimization-Machine-Learning/dp/0201157675/ref=sr_1_sc_1?ie=UTF8&qid=1520628364&sr=8-1-spell&keywords=Genetic+Algortithms+in+search) +* [Wikipedia](https://en.wikipedia.org/wiki/Genetic_algorithm) +* [My Original Gist](https://gist.github.com/blainerothrock/efda6e12fe10792c99c990f8ff3daeba) ## The Code @@ -141,7 +143,7 @@ func weightedChoice(items:[(item:[UInt8], weight:Double)]) -> (item:[UInt8], wei } ``` -The above function takes a list of individuals with their calculated fitness. Then selects one at random offset by their fitness value. +The above function takes a list of individuals with their calculated fitness. Then selects one at random offset by their fitness value. The horrible 1,000,000 multiplication and division is to insure precision by calculating decimals. `arc4random` only uses integers so this is required to convert to a precise Double, it's not perfect, but enough for our example. ## Mutation @@ -168,19 +170,16 @@ This allows for a population to explore all the possibilities of it's building b ## Crossover -Crossover, the sexy part of a GA, is how offspring are created from 2 selected individuals in the current population. This is done by splitting the parents into 2 parts, then combining 1 part from each parent to create the offspring. To promote diversity, we randomly select a index to split the parents: +Crossover, the sexy part of a GA, is how offspring are created from 2 selected individuals in the current population. This is done by splitting the parents into 2 parts, then combining 1 part from each parent to create the offspring. To promote diversity, we randomly select a index to split the parents. ```swift -func crossover(dna1:[UInt8], dna2:[UInt8], dnaSize:Int) -> (dna1:[UInt8], dna2:[UInt8]) { +func crossover(dna1:[UInt8], dna2:[UInt8], dnaSize:Int) -> [UInt8] { let pos = Int(arc4random_uniform(UInt32(dnaSize-1))) let dna1Index1 = dna1.index(dna1.startIndex, offsetBy: pos) let dna2Index1 = dna2.index(dna2.startIndex, offsetBy: pos) - return ( - [UInt8](dna1.prefix(upTo: dna1Index1) + dna2.suffix(from: dna2Index1)), - [UInt8](dna2.prefix(upTo: dna2Index1) + dna1.suffix(from: dna1Index1)) - ) + return [UInt8](dna1.prefix(upTo: dna1Index1) + dna2.suffix(from: dna2Index1)) } ``` @@ -203,7 +202,7 @@ for generation in 0...GENERATIONS { } ``` -Now, for each individual in the population, we need to calculate its fitness and weighted value. For weighted choice we store the fitness as a percent `1 / fitness`. +Now, for each individual in the population, we need to calculate its fitness and weighted value. Since 0 is the best value we will use `1/fitness` to represent the weighted value. Note this is not a percent, but just how much more likely the value is to be selected over others. If the highest number was the most fit, the weight calculation would be `fitness/totalFitness`, which would be a percent. ```swift var weightedPopulation = [(item:[UInt8], weight:Double)]() @@ -215,24 +214,118 @@ for individual in population { } ``` -To understand weighted choice, let walk though a smaller example, let's say we have the following population, where 0 is the best fitness: +From here we can start to build the next generation. -```txt -1: 10 -2: 5 -3: 4 -4: 7 -5: 11 +```swift +var nextGeneration = [] +``` + +The below loop is where we pull everything together. We loop for `POP_SIZE`, selecting 2 individuals by weighted choice, crossover their values to produce a offspring, then finial subject the new individual to mutation. Once completed we have a completely new generation based on the last generation. + +```swift +0...POP_SIZE).forEach { _ in + let ind1 = weightedChoice(items: weightedPopulation) + let ind2 = weightedChoice(items: weightedPopulation) + + let offspring = crossover(dna1: ind1.item, dna2: ind2.item, dnaSize: DNA_SIZE) + + // append to the population and mutate + nextGeneration.append(mutate(lexicon: lex, dna: offspring, mutationChance: MUTATION_CHANCE)) +} +``` + +The final piece to the main loop is to select the fittest individual of a population: + +```swift +fittest = population[0] +var minFitness = calculateFitness(dna: fittest, optimal: OPTIMAL) + +for indv in population {lex + let indvFitness = calculateFitness(dna: indv, optimal: OPTIMAL) + if indvFitness < minFitness { + fittest = indv + minFitness = indvFitness + } +} +if minFitness == 0 { break; } +print("\(generation): \(String(bytes: fittest, encoding: .utf8)!)") ``` -Now here is the weight of each: +Since we know the fittest string, I've added a `break` to kill the program if we find it. At the end of a loop at a print statement for the fittest string: -```txt -1: -2: -3: -4: -5: +```swift +print("fittest string: \(String(bytes: fittest, encoding: .utf8)!)") +``` -total = +Now we can run the program! Playgrounds are a nice place to develop, but are going to run this program **very slow**. I highly suggest running in Terminal: `swift gen.swift`. When running you should see something like this and it should not take too long to get `Hello, World`: + +```text +0: RXclh F HDko +1: DkyssjgElk]; +2: TiM4u) DrKvZ +3: Dkysu) DrKvZ +4: -kysu) DrKvZ +5: Tlwsu) DrKvZ +6: Tlwsu) Drd}k +7: Tlwsu) Drd}k +8: Tlwsu) Drd}k +9: Tlwsu) Drd}k +10: G^csu) |zd}k +11: G^csu) |zdko +12: G^csu) |zdko +13: Dkysu) Drd}k +14: G^wsu) `rd}k +15: Dkysu) `rdko +16: Dkysu) `rdko +17: Glwsu) `rdko +18: TXysu) `rdkc +19: U^wsu) `rdko +20: G^wsu) `rdko +21: Glysu) `rdko +22: G^ysu) `rdko +23: G^ysu) `ryko +24: G^wsu) `rdko +25: G^wsu) `rdko +26: G^wsu) `rdko +... +1408: Hello, Wormd +1409: Hello, Wormd +1410: Hello, Wormd +1411: Hello, Wormd +1412: Hello, Wormd +1413: Hello, Wormd +1414: Hello, Wormd +1415: Hello, Wormd +1416: Hello, Wormd +1417: Hello, Wormd +1418: Hello, Wormd +1419: Hello, Wormd +1420: Hello, Wormd +1421: Hello, Wormd +1422: Hello, Wormd +1423: Hello, Wormd +1424: Hello, Wormd +1425: Hello, Wormd +1426: Hello, Wormd +1427: Hello, Wormd +1428: Hello, Wormd +1429: Hello, Wormd +1430: Hello, Wormd +1431: Hello, Wormd +1432: Hello, Wormd +1433: Hello, Wormd +1434: Hello, Wormd +1435: Hello, Wormd +fittest string: Hello, World ``` + +How long it takes will vary since this is based on randomization, but it should almost always finish in under 5000 generations. Woo! + + +## Now What? + +We did it, we have a running simple genetic algorithm. Take some time a play around with the global variables, `POP_SIZE`, `OPTIMAL`, `MUTATION_CHANCE`, `GENERATIONS`. Just make sure to only add characters that are in the lexicon, but go ahead and update too! + +For an example let's try something much longer: `Ray Wenderlich's Swift Algorithm Club Rocks`. Plug that string into `OPTIMAL` and change `GENERATIONS` to `10000`. You'll be able to see that the we are getting somewhere, but you most likely will not reach the optimal string in 10,000 generations. Since we have a larger string let's raise our mutation chance to `200` (1/2 as likely to mutate). You may not get there, but you should get a lot closer than before. With a longer string, too much mutate can make it hard for fit strings to survive. Now try either upping `POP_SIZE` or increase `GENERATIONS`. Either way you should eventually get the value, but there will be a "sweet spot" for an individual of a certain size. + +Please submit any kind of update to this tutorial or add more examples! diff --git a/Genetic/gen.playground/Contents.swift b/Genetic/gen.playground/Contents.swift index 4c67f8bd1..8e1976ca6 100644 --- a/Genetic/gen.playground/Contents.swift +++ b/Genetic/gen.playground/Contents.swift @@ -63,7 +63,7 @@ func calculateFitness(dna:[UInt8], optimal:[UInt8]) -> Int { calculateFitness(dna: "Gello, World".asciiArray, optimal: "Hello, World".asciiArray) func weightedChoice(items:[(item:[UInt8], weight:Double)]) -> (item:[UInt8], weight:Double) { - + let total = items.reduce(0.0) { return $0 + $1.weight} var n = Double(arc4random_uniform(UInt32(total * 1000000.0))) / 1000000.0 @@ -91,16 +91,13 @@ func mutate(lexicon: [UInt8], dna:[UInt8], mutationChance:Int) -> [UInt8] { } -func crossover(dna1:[UInt8], dna2:[UInt8], dnaSize:Int) -> (dna1:[UInt8], dna2:[UInt8]) { +func crossover(dna1:[UInt8], dna2:[UInt8], dnaSize:Int) -> [UInt8] { let pos = Int(arc4random_uniform(UInt32(dnaSize-1))) let dna1Index1 = dna1.index(dna1.startIndex, offsetBy: pos) let dna2Index1 = dna2.index(dna2.startIndex, offsetBy: pos) - return ( - [UInt8](dna1.prefix(upTo: dna1Index1) + dna2.suffix(from: dna2Index1)), - [UInt8](dna2.prefix(upTo: dna2Index1) + dna1.suffix(from: dna1Index1)) - ) + return [UInt8](dna1.prefix(upTo: dna1Index1) + dna2.suffix(from: dna2Index1)) } func main() { @@ -111,7 +108,7 @@ func main() { var fittest = [UInt8]() for generation in 0...GENERATIONS { - print("Generation \(generation) with random sample: \(String(bytes: population[0], encoding:.ascii)!)") + // print("Generation \(generation) with random sample: \(String(bytes: population[0], encoding:.ascii)!)") var weightedPopulation = [(item:[UInt8], weight:Double)]() @@ -120,7 +117,7 @@ func main() { for individual in population { let fitnessValue = calculateFitness(dna: individual, optimal: OPTIMAL) - let pair = ( individual, fitnessValue == 0 ? 1.0 : 1.0/Double( fitnessValue ) ) + let pair = ( individual, fitnessValue == 0 ? 1.0 : Double(100/POP_SIZE)/Double( fitnessValue ) ) weightedPopulation.append(pair) } @@ -128,15 +125,14 @@ func main() { population = [] // create a new generation using the individuals in the origional population - for _ in 0...POP_SIZE/2 { + (0...POP_SIZE).forEach { _ in let ind1 = weightedChoice(items: weightedPopulation) let ind2 = weightedChoice(items: weightedPopulation) let offspring = crossover(dna1: ind1.item, dna2: ind2.item, dnaSize: DNA_SIZE) // append to the population and mutate - population.append(mutate(lexicon: lex, dna: offspring.dna1, mutationChance: MUTATION_CHANCE)) - population.append(mutate(lexicon: lex, dna: offspring.dna2, mutationChance: MUTATION_CHANCE)) + population.append(mutate(lexicon: lex, dna: offspring, mutationChance: MUTATION_CHANCE)) } fittest = population[0] @@ -151,6 +147,11 @@ func main() { } } if minFitness == 0 { break; } + print("\(generation): \(String(bytes: fittest, encoding: .utf8)!)") + } - print("fittest string: \(String(bytes: fittest, encoding: .ascii)!)") + print("fittest string: \(String(bytes: fittest, encoding: .utf8)!)") } + +main() + diff --git a/Genetic/gen.swift b/Genetic/gen.swift index f664fd5f7..a2a1b1410 100644 --- a/Genetic/gen.swift +++ b/Genetic/gen.swift @@ -18,7 +18,7 @@ let OPTIMAL:[UInt8] = "Hello, World".asciiArray let DNA_SIZE = OPTIMAL.count // size of each generation -let POP_SIZE = 200 +let POP_SIZE = 50 // max number of generations, script will stop when it reach 5000 if the optimal value is not found let GENERATIONS = 5000 @@ -91,16 +91,13 @@ func mutate(lexicon: [UInt8], dna:[UInt8], mutationChance:Int) -> [UInt8] { } -func crossover(dna1:[UInt8], dna2:[UInt8], dnaSize:Int) -> (dna1:[UInt8], dna2:[UInt8]) { +func crossover(dna1:[UInt8], dna2:[UInt8], dnaSize:Int) -> [UInt8] { let pos = Int(arc4random_uniform(UInt32(dnaSize-1))) let dna1Index1 = dna1.index(dna1.startIndex, offsetBy: pos) let dna2Index1 = dna2.index(dna2.startIndex, offsetBy: pos) - return ( - [UInt8](dna1.prefix(upTo: dna1Index1) + dna2.suffix(from: dna2Index1)), - [UInt8](dna2.prefix(upTo: dna2Index1) + dna1.suffix(from: dna1Index1)) - ) + return [UInt8](dna1.prefix(upTo: dna1Index1) + dna2.suffix(from: dna2Index1)) } func main() { @@ -128,15 +125,14 @@ func main() { population = [] // create a new generation using the individuals in the origional population - for _ in 0...POP_SIZE/2 { + (0...POP_SIZE).forEach { _ in let ind1 = weightedChoice(items: weightedPopulation) let ind2 = weightedChoice(items: weightedPopulation) let offspring = crossover(dna1: ind1.item, dna2: ind2.item, dnaSize: DNA_SIZE) // append to the population and mutate - population.append(mutate(lexicon: lex, dna: offspring.dna1, mutationChance: MUTATION_CHANCE)) - population.append(mutate(lexicon: lex, dna: offspring.dna2, mutationChance: MUTATION_CHANCE)) + population.append(mutate(lexicon: lex, dna: offspring, mutationChance: MUTATION_CHANCE)) } fittest = population[0] @@ -151,11 +147,10 @@ func main() { } } if minFitness == 0 { break; } - if generation % 1000 == 0 { - print("\(generation): \(String(bytes: fittest, encoding: .utf8)!)") - } + print("\(generation): \(String(bytes: fittest, encoding: .utf8)!)") + } - print("fittest string: \(String(bytes: fittest, encoding: .ascii)!)") + print("fittest string: \(String(bytes: fittest, encoding: .utf8)!)") } main() From ca6f0f0c71773a9117db63546b7c94b0c8de3a0e Mon Sep 17 00:00:00 2001 From: Blaine Rothrock Date: Fri, 9 Mar 2018 15:32:58 -0600 Subject: [PATCH 018/271] readme updates --- Genetic/README.markdown | 79 ++++++++++++++++++++--------------------- 1 file changed, 38 insertions(+), 41 deletions(-) diff --git a/Genetic/README.markdown b/Genetic/README.markdown index 92f121daa..d6a474a10 100644 --- a/Genetic/README.markdown +++ b/Genetic/README.markdown @@ -2,35 +2,34 @@ individual# Genetic Algorthim ## What is it? -A genetic algorithm (GA) is process inspired by natural selection to find high quality solutions. Most commonly used for optimization. GAs rely on the bio-inspired processes of natural selection, more specifically the process of selection (fitness), mutation and crossover. To understand more, let's walk through these process in terms of biology: +A genetic algorithm (GA) is process inspired by natural selection to find high quality solutions. Most commonly used for optimization. GAs rely on the bio-inspired processes of natural selection, more specifically the process of selection (fitness), crossover and mutation. To understand more, let's walk through these processes in terms of biology: ### Selection >**Selection**, in biology, the preferential survival and reproduction or preferential elimination of individuals with certain genotypes (genetic compositions), by means of natural or artificial controlling factors. [Britannica](britannica) -In other words, survival of the fittest. Organism that survive in their environment tend to reproduce more. With GAs we generate a fitness model that will rank offspring and give them a better chance for reproduction. - -### Mutation ->**Mutation**, an alteration in the genetic material (the genome) of a cell of a living organism or of a virus that is more or less permanent and that can be transmitted to the cell’s or the virus’s descendants. [Britannica](https://www.britannica.com/science/mutation-genetics) - -The randomization that allows for organisms to change over time. In GAs we build a randomization process that will mutate offspring in a populate in order to randomly introduce fitness variance. +In other words, survival of the fittest. Organisms that survive in their environment tend to reproduce more. With GAs we generate a fitness model that will rank individuals and give them a better chance for reproduction. ### Crossover >**Chromosomal crossover** (or crossing over) is the exchange of genetic material between homologous chromosomes that results in recombinant chromosomes during sexual reproduction [Wikipedia](https://en.wikipedia.org/wiki/Chromosomal_crossover) -Simply reproduction. A generation will a mixed representation of the previous generation, with offspring taking data (DNA) from both parents. GAs do this by randomly, but weightily, mating offspring to create new generations. +Simply reproduction. A generation will be a mixed representation of the previous generation, with offspring taking DNA from both parents. GAs do this by randomly, but weightily, mating offspring to create new generations. + +### Mutation +>**Mutation**, an alteration in the genetic material (the genome) of a cell of a living organism or of a virus that is more or less permanent and that can be transmitted to the cell’s or the virus’s descendants. [Britannica](https://www.britannica.com/science/mutation-genetics) + +The randomization that allows for organisms to change over time. In GAs we build a randomization process that will mutate offspring in a population in order to introduce fitness variance. ### Resources: * [Genetic Algorithms in Search Optimization, and Machine Learning](https://www.amazon.com/Genetic-Algorithms-Optimization-Machine-Learning/dp/0201157675/ref=sr_1_sc_1?ie=UTF8&qid=1520628364&sr=8-1-spell&keywords=Genetic+Algortithms+in+search) * [Wikipedia](https://en.wikipedia.org/wiki/Genetic_algorithm) * [My Original Gist](https://gist.github.com/blainerothrock/efda6e12fe10792c99c990f8ff3daeba) - ## The Code ### Problem -For this quick and dirty example, we are going to obtain a optimize string using a simple genetic algorithm. More specifically we are trying to take a randomly generated origin string of a fixed length and evolve it into the most optimized string of our choosing. +For this quick and dirty example, we are going to produce an optimized string using a simple genetic algorithm. More specifically we are trying to take a randomly generated origin string of a fixed length and evolve it into the most optimized string of our choosing. -We will be creating a bio-inspired world where the absolute existence is string `Hello, World!`. Nothing in this universe is better and it's our goal to get as close to it as possible. +We will be creating a bio-inspired world where the absolute existence is the string `Hello, World!`. Nothing in this universe is better and it's our goal to get as close to it as possible to ensure survival. ### Define the Universe @@ -40,36 +39,32 @@ Before we dive into the core processes we need to set up our "universe". First l let lex: [UInt8] = " !\"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~".asciiArray ``` -To make things easier, we are actually going to work in ASCII values, so let's define a String extension to help with that. +To make things easier, we are actually going to work in [Unicode values](https://en.wikipedia.org/wiki/List_of_Unicode_characters), so let's define a String extension to help with that. ```swift extension String { - var asciiArray: [UInt8] { + var unicodeArray: [UInt8] { return [UInt8](self.utf8) } } ``` Now, let's define a few global variables for the universe: + * `OPTIMAL`: This is the end goal and what we will be using to rate fitness. In the real world this will not exist + * `DNA_SIZE`: The length of the string in our population. Organisms need to be similar + * `POP_SIZE`: Size of each generation + * `MAX_GENERATIONS`: Max number of generations, script will stop when it reach 5000 if the optimal value is not found + * `MUTATION_CHANCE`: The chance in which a random nucleotide can mutate (`1/MUTATION_CHANCE`) ```swift -// This is the end goal and what we will be using to rate fitness. In the real world this will not exist -let OPTIMAL:[UInt8] = "Hello, World".asciiArray - -// The length of the string in our population. Organisms need to be similar +let OPTIMAL:[UInt8] = "Hello, World".unicodeArray let DNA_SIZE = OPTIMAL.count - -// size of each generation let POP_SIZE = 50 - -// max number of generations, script will stop when it reach 5000 if the optimal value is not found -let GENERATIONS = 5000 - -// The chance in which a random nucleotide can mutate (1/n) +let MAX_GENERATIONS = 5000 let MUTATION_CHANCE = 100 ``` - The last piece we need for set up is a function to give us a random ASCII value from our lexicon: + The last piece we need for set up is a function to give us a random unicode value from our lexicon: ```swift func randomChar(from lexicon: [UInt8]) -> UInt8 { @@ -78,10 +73,12 @@ let MUTATION_CHANCE = 100 return lexicon[rand] } ``` + + **Note**: `arc4random_uniform` is strickly used in this example. It would be fun to play around with some of the [randomization in GameKit](https://developer.apple.com/library/content/documentation/General/Conceptual/GameplayKit_Guide/RandomSources.html) ### Population Zero - Before selecting, mutating and reproduction, we need population to start with. Now that we have the universe defined we can write that function: +Before selecting, crossover and mutation, we need a population to start with. Now that we have the universe defined we can write that function: ```swift func randomPopulation(from lexicon: [UInt8], populationSize: Int, dnaSize: Int) -> [[UInt8]] { @@ -90,9 +87,9 @@ let MUTATION_CHANCE = 100 var pop = [[UInt8]]() - for _ in 0.. Int { var fitness = 0 - for c in 0...dna.count-1 { + (0...dna.count-1).forEach { c in fitness += abs(Int(dna[c]) - Int(optimal[c])) } return fitness } ``` -The above will produce a fitness value to an individual. The perfect solution, "Hello, World" will have a fitness of 0. "Gello, World" will have a fitness of 1 since it is one ASCII value off from the optimal. +The above will produce a fitness value to an individual. The perfect solution, "Hello, World" will have a fitness of 0. "Gello, World" will have a fitness of 1 since it is one unicode value off from the optimal (`H->G`). -This example is very, but it'll work for our example. In a real world problem, the optimal solution is unknown or impossible. [Here](https://iccl.inf.tu-dresden.de/w/images/b/b7/GA_for_TSP.pdf) is a paper about optimizing a solution for the famous [traveling salesman problem](https://en.wikipedia.org/wiki/Travelling_salesman_problem) using GA. In this example the problem is unsolvable by modern computers, but you can rate a individual solution by distance traveled. The optimal fitness here is an impossible 0. The closer the solution is to 0, the better chance for survival. +This example is very simple, but it'll work for our example. In a real world problem, the optimal solution is unknown or impossible. [Here](https://iccl.inf.tu-dresden.de/w/images/b/b7/GA_for_TSP.pdf) is a paper about optimizing a solution for the famous [traveling salesman problem](https://en.wikipedia.org/wiki/Travelling_salesman_problem) using a GA. In this example the problem is unsolvable by modern computers, but you can rate a individual solution by distance traveled. The optimal fitness here is an impossible 0. The closer the solution is to 0, the better chance for survival. In our example we will reach our goal, a fitness of 0. -The second part to selection is weighted choice, also called roulette wheel selection. This defines how individuals are selected for the reproduction process out of the current population. Just because you are the best choice for natural selection doesn't mean the environment will select you. The individual could fall off a cliff, get dysentery or not be able to reproduce. +The second part to selection is weighted choice, also called roulette wheel selection. This defines how individuals are selected for the reproduction process out of the current population. Just because you are the best choice for natural selection doesn't mean the environment will select you. The individual could fall off a cliff, get dysentery or be unable to reproduce. -Let's take a second and ask why on this one. Why would you not always want to select the most fit from a population? It's hard to see from this simple example, but let's think about dog breeding, because breeders remove this process and hand select dogs for the next generation. As a result you get improved desired characteristics, but the individuals will also continue to carry genetic disorders that come along with those traits. This is essentially leading the evolution down a linear path. A certain "branch" of evolution may beat out the current fittest solution at a later time. +Let's take a second and ask why on this one. Why would you not always want to select the most fit from a population? It's hard to see from this simple example, but let's think about dog breeding, because breeders remove this process and hand select dogs for the next generation. As a result you get improved desired characteristics, but the individuals will also continue to carry genetic disorders that come along with those traits. A certain "branch" of evolution may beat out the current fittest solution at a later time. This may be ok depending on the problem, but to keep this educational we will go with the bio-inspired way. -ok, back to code. Here is our weighted choice function: +With all that, here is our weight choice function: ```swift func weightedChoice(items:[(item:[UInt8], weight:Double)]) -> (item:[UInt8], weight:Double) { @@ -147,13 +144,13 @@ The above function takes a list of individuals with their calculated fitness. Th ## Mutation -The all powerful mutation. The great randomization that turns bacteria into humans, just add time. So powerful yet so simple: +The all powerful mutation, the thing that introduces otherwise non exisitant fitness variance. It can either hurt of improve a individuals fitness but over time it will cause evolution towards more fit populations. Imagine if our initial random population was missing the charachter `H`, in that case we need to rely on mutation to introduce that character into the population in order to achive the optimal solution. ```swift func mutate(lexicon: [UInt8], dna:[UInt8], mutationChance:Int) -> [UInt8] { var outputDna = dna - for i in 0.. Date: Fri, 9 Mar 2018 15:43:15 -0600 Subject: [PATCH 019/271] typos --- Genetic/README.markdown | 30 +++++++------- Genetic/gen.playground/Contents.swift | 39 +++++++------------ Genetic/gen.swift | 56 ++++++++++++--------------- 3 files changed, 53 insertions(+), 72 deletions(-) diff --git a/Genetic/README.markdown b/Genetic/README.markdown index d6a474a10..07547c4b4 100644 --- a/Genetic/README.markdown +++ b/Genetic/README.markdown @@ -29,7 +29,7 @@ The randomization that allows for organisms to change over time. In GAs we build ### Problem For this quick and dirty example, we are going to produce an optimized string using a simple genetic algorithm. More specifically we are trying to take a randomly generated origin string of a fixed length and evolve it into the most optimized string of our choosing. -We will be creating a bio-inspired world where the absolute existence is the string `Hello, World!`. Nothing in this universe is better and it's our goal to get as close to it as possible to ensure survival. +We will be creating a bio-inspired world where the absolute existence is the string `Hello, World!`. Nothing in this universe is better and it's our goal to get as close to it as possible to ensure survival. ### Define the Universe @@ -73,8 +73,8 @@ let MUTATION_CHANCE = 100 return lexicon[rand] } ``` - - **Note**: `arc4random_uniform` is strickly used in this example. It would be fun to play around with some of the [randomization in GameKit](https://developer.apple.com/library/content/documentation/General/Conceptual/GameplayKit_Guide/RandomSources.html) + + **Note**: `arc4random_uniform` is strictly used in this example. It would be fun to play around with some of the [randomization in GameKit](https://developer.apple.com/library/content/documentation/General/Conceptual/GameplayKit_Guide/RandomSources.html) ### Population Zero @@ -83,8 +83,6 @@ Before selecting, crossover and mutation, we need a population to start with. No ```swift func randomPopulation(from lexicon: [UInt8], populationSize: Int, dnaSize: Int) -> [[UInt8]] { - let len = UInt32(lexicon.count) - var pop = [[UInt8]]() (0.. (item:[UInt8], weight:Double) { +func weightedChoice(items:[(dna:[UInt8], weight:Double)]) -> (dna:[UInt8], weight:Double) { let total = items.reduce(0.0) { return $0 + $1.weight} var n = Double(arc4random_uniform(UInt32(total * 1000000.0))) / 1000000.0 - for itemTuple in items { - if n < itemTuple.weight { - return itemTuple + for item in items { + if n < item.weight { + return item } - n = n - itemTuple.weight + n = n - item.weight } return items[1] } @@ -144,7 +142,7 @@ The above function takes a list of individuals with their calculated fitness. Th ## Mutation -The all powerful mutation, the thing that introduces otherwise non exisitant fitness variance. It can either hurt of improve a individuals fitness but over time it will cause evolution towards more fit populations. Imagine if our initial random population was missing the charachter `H`, in that case we need to rely on mutation to introduce that character into the population in order to achive the optimal solution. +The all powerful mutation, the thing that introduces otherwise non existent fitness variance. It can either hurt of improve a individuals fitness but over time it will cause evolution towards more fit populations. Imagine if our initial random population was missing the charachter `H`, in that case we need to rely on mutation to introduce that character into the population in order to achieve the optimal solution. ```swift func mutate(lexicon: [UInt8], dna:[UInt8], mutationChance:Int) -> [UInt8] { @@ -184,7 +182,7 @@ The above is used to generate a completely new generation based on the current g ## Putting it all together -- Running the Genetic Algorithm -We now have all the functions we need to kick off the algorthim. Let's start from the beginning, first we need a random population to serve as a starting point. We will also initialize a fittest variable to hold the fittest individual, we will initialize it with the first individual of our random population. +We now have all the functions we need to kick off the algorithm. Let's start from the beginning, first we need a random population to serve as a starting point. We will also initialize a fittest variable to hold the fittest individual, we will initialize it with the first individual of our random population. ```swift var population:[[UInt8]] = randomPopulation(from: lex, populationSize: POP_SIZE, dnaSize: DNA_SIZE) @@ -202,7 +200,7 @@ for generation in 0...GENERATIONS { Now, for each individual in the population, we need to calculate its fitness and weighted value. Since 0 is the best value we will use `1/fitness` to represent the weight. Note this is not a percent, but just how much more likely the value is to be selected over others. If the highest number was the most fit, the weight calculation would be `fitness/totalFitness`, which would be a percent. ```swift -var weightedPopulation = [(item:[UInt8], weight:Double)]() +var weightedPopulation = [(dna:[UInt8], weight:Double)]() for individual in population { let fitnessValue = calculateFitness(dna: individual, optimal: OPTIMAL) @@ -224,7 +222,7 @@ The below loop is where we pull everything together. We loop for `POP_SIZE`, sel let ind1 = weightedChoice(items: weightedPopulation) let ind2 = weightedChoice(items: weightedPopulation) - let offspring = crossover(dna1: ind1.item, dna2: ind2.item, dnaSize: DNA_SIZE) + let offspring = crossover(dna1: ind1.dna, dna2: ind2.dna, dnaSize: DNA_SIZE) // append to the population and mutate nextGeneration.append(mutate(lexicon: lex, dna: offspring, mutationChance: MUTATION_CHANCE)) @@ -237,7 +235,7 @@ The final piece to the main loop is to select the fittest individual of a popula fittest = population[0] var minFitness = calculateFitness(dna: fittest, optimal: OPTIMAL) -for indv in population {lex +population.forEach { indv in let indvFitness = calculateFitness(dna: indv, optimal: OPTIMAL) if indvFitness < minFitness { fittest = indv diff --git a/Genetic/gen.playground/Contents.swift b/Genetic/gen.playground/Contents.swift index 8e1976ca6..79a398ceb 100644 --- a/Genetic/gen.playground/Contents.swift +++ b/Genetic/gen.playground/Contents.swift @@ -3,16 +3,16 @@ import Foundation extension String { - var asciiArray: [UInt8] { + var unicodeArray: [UInt8] { return [UInt8](self.utf8) } } -let lex: [UInt8] = " !\"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~".asciiArray +let lex: [UInt8] = " !\"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~".unicodeArray // This is the end goal and what we will be using to rate fitness. In the real world this will not exist -let OPTIMAL:[UInt8] = "Hello, World".asciiArray +let OPTIMAL:[UInt8] = "Hello, World".unicodeArray // The length of the string in our population. Organisms need to be similar let DNA_SIZE = OPTIMAL.count @@ -34,13 +34,11 @@ func randomChar(from lexicon: [UInt8]) -> UInt8 { func randomPopulation(from lexicon: [UInt8], populationSize: Int, dnaSize: Int) -> [[UInt8]] { - let len = UInt32(lexicon.count) - var pop = [[UInt8]]() - for _ in 0.. Int { - var fitness = 0 - for c in 0...dna.count-1 { + (0...dna.count-1).forEach { c in fitness += abs(Int(dna[c]) - Int(optimal[c])) } return fitness } -calculateFitness(dna: "Gello, World".asciiArray, optimal: "Hello, World".asciiArray) - -func weightedChoice(items:[(item:[UInt8], weight:Double)]) -> (item:[UInt8], weight:Double) { +func weightedChoice(items:[(dna:[UInt8], weight:Double)]) -> (dna:[UInt8], weight:Double) { let total = items.reduce(0.0) { return $0 + $1.weight} var n = Double(arc4random_uniform(UInt32(total * 1000000.0))) / 1000000.0 - for itemTuple in items { - if n < itemTuple.weight { - return itemTuple + for item in items { + if n < item.weight { + return item } - n = n - itemTuple.weight + n = n - item.weight } return items[1] } @@ -80,7 +73,7 @@ func weightedChoice(items:[(item:[UInt8], weight:Double)]) -> (item:[UInt8], wei func mutate(lexicon: [UInt8], dna:[UInt8], mutationChance:Int) -> [UInt8] { var outputDna = dna - for i in 0..?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~".asciiArray +let lex: [UInt8] = " !\"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~".unicodeArray // This is the end goal and what we will be using to rate fitness. In the real world this will not exist -let OPTIMAL:[UInt8] = "Hello, World".asciiArray +let OPTIMAL:[UInt8] = "Hello, World".unicodeArray // The length of the string in our population. Organisms need to be similar let DNA_SIZE = OPTIMAL.count @@ -34,45 +34,38 @@ func randomChar(from lexicon: [UInt8]) -> UInt8 { func randomPopulation(from lexicon: [UInt8], populationSize: Int, dnaSize: Int) -> [[UInt8]] { - let len = UInt32(lexicon.count) - - var pop = [[UInt8]]() - - for _ in 0.. Int { - var fitness = 0 - for c in 0...dna.count-1 { + (0...dna.count-1).forEach { c in fitness += abs(Int(dna[c]) - Int(optimal[c])) } return fitness } -calculateFitness(dna: "Gello, World".asciiArray, optimal: "Hello, World".asciiArray) - -func weightedChoice(items:[(item:[UInt8], weight:Double)]) -> (item:[UInt8], weight:Double) { +func weightedChoice(items:[(dna:[UInt8], weight:Double)]) -> (dna:[UInt8], weight:Double) { let total = items.reduce(0.0) { return $0 + $1.weight} var n = Double(arc4random_uniform(UInt32(total * 1000000.0))) / 1000000.0 - for itemTuple in items { - if n < itemTuple.weight { - return itemTuple + for item in items { + if n < item.weight { + return item } - n = n - itemTuple.weight + n = n - item.weight } return items[1] } @@ -80,7 +73,7 @@ func weightedChoice(items:[(item:[UInt8], weight:Double)]) -> (item:[UInt8], wei func mutate(lexicon: [UInt8], dna:[UInt8], mutationChance:Int) -> [UInt8] { var outputDna = dna - for i in 0.. Date: Fri, 9 Mar 2018 16:05:03 -0600 Subject: [PATCH 020/271] MAX_GENERATIONS --- Genetic/gen.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Genetic/gen.swift b/Genetic/gen.swift index aad499d04..a61e61785 100644 --- a/Genetic/gen.swift +++ b/Genetic/gen.swift @@ -21,7 +21,7 @@ let DNA_SIZE = OPTIMAL.count let POP_SIZE = 50 // max number of generations, script will stop when it reach 5000 if the optimal value is not found -let GENERATIONS = 5000 +let MAX_GENERATIONS = 5000 // The chance in which a random nucleotide can mutate (1/n) let MUTATION_CHANCE = 100 @@ -100,7 +100,7 @@ func main() { // print("population: \(population), dnaSize: \(DNA_SIZE) ") var fittest = [UInt8]() - for generation in 0...GENERATIONS { + for generation in 0...MAX_GENERATIONS { var weightedPopulation = [(dna:[UInt8], weight:Double)]() From 0bcbd08988c5ab000a9901c6a6c03ab1a29aed6a Mon Sep 17 00:00:00 2001 From: Kelvin Lau Date: Sun, 11 Mar 2018 12:59:19 -0700 Subject: [PATCH 021/271] Grammar fixes for first bit. --- Myers Difference Algorithm/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Myers Difference Algorithm/README.md b/Myers Difference Algorithm/README.md index 2f6c3c579..a9d92a227 100644 --- a/Myers Difference Algorithm/README.md +++ b/Myers Difference Algorithm/README.md @@ -1,6 +1,6 @@ # Myers Difference Algorithm -Myers Difference Algorithm is the algorithm to find a longest common subsequence or shortest edit scripts (LCS/SES dual probrem) of two sequences by a simple O(ND) time, where N is the sum of the lengths of the two sequences. Common subsequence is the sequence of elements that appear in the same order in both sequences. Edit script will be discussed below. +Myers Difference Algorithm is an algorithm that finds a longest common subsequence or shortest edit scripts (LCS/SES dual probrem) of two sequences. MDA can accomplish this in O(ND) time, where N is the sum of the lengths of the two sequences. The common subsequence of two sequences is the sequence of elements that appear in the same order in both sequences. The edit scripts will be discussed below. For example, assuming that sequence `A = ["1", "2", "3"]` and sequence `B = ["2", "3", "4"]`, `["2"], ["2", "3"]` are common sequences. Furthermore, the latter `["2", "3"]` is the longest common subsequence. But `["1", "2"], ["3", "2"]` are not. Because, `["1", "2"]` contains `"1"` that is not included in `B`, `["3", "2"]` has elements are included in both, but the appearing order is not correct. From 90afdf77d5fe66f20f1d68f38c9cf24d8070f363 Mon Sep 17 00:00:00 2001 From: Kelvin Lau Date: Sun, 11 Mar 2018 13:07:53 -0700 Subject: [PATCH 022/271] Couple more edits. --- Myers Difference Algorithm/README.md | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/Myers Difference Algorithm/README.md b/Myers Difference Algorithm/README.md index a9d92a227..c1aa2da3a 100644 --- a/Myers Difference Algorithm/README.md +++ b/Myers Difference Algorithm/README.md @@ -1,20 +1,32 @@ # Myers Difference Algorithm -Myers Difference Algorithm is an algorithm that finds a longest common subsequence or shortest edit scripts (LCS/SES dual probrem) of two sequences. MDA can accomplish this in O(ND) time, where N is the sum of the lengths of the two sequences. The common subsequence of two sequences is the sequence of elements that appear in the same order in both sequences. The edit scripts will be discussed below. +Myers Difference Algorithm is an algorithm that finds a longest common subsequence(LCS) or shortest edit scripts(SES) of two sequences. MDA can accomplish this in O(ND) time, where N is the sum of the lengths of the two sequences. The common subsequence of two sequences is the sequence of elements that appear in the same order in both sequences. -For example, assuming that sequence `A = ["1", "2", "3"]` and sequence `B = ["2", "3", "4"]`, `["2"], ["2", "3"]` are common sequences. Furthermore, the latter `["2", "3"]` is the longest common subsequence. But `["1", "2"], ["3", "2"]` are not. Because, `["1", "2"]` contains `"1"` that is not included in `B`, `["3", "2"]` has elements are included in both, but the appearing order is not correct. +For example, let's assume you have two arrays: + +``` +A = [1, 2, 3] +B = [2, 3, 4] +``` + +The common subsequences of these two arrays are `[2]`, and `[2,3]`. The longest common sequence in this case is `[2,3]`. ## Finding the length of the Longest Common Subsequence with Myers Algorithm on Edit Graph ### Edit Graph -Myers Algorithm uses Edit Graph for solving LCS/SES problem. Edit Graph is the graph like below. +MDA uses an **Edit Graph** to solve the LCS/SES problem. Below is a illustration depicting an edit graph: -Here, we think about the length of the LCS of sequences `X = [A, B, C, A, B, B, A]`, `Y = [C, B, A, B, A, C]`. +In this case, the arrays are: + +``` +X = [A, B, C, A, B, B, A] +Y = [C, B, A, B, A, C] +``` -In Myers Algorithm, edit graph are prepared by +MDA generates the edit graph through the following steps: 1. Line the element of sequence `X` on the x axis. And do for `Y` on the y axis. 2. Make grid and vertex at each point in the grid (x, y), `x in [0, N] and y in [0, M]`. `N` is the length of sequence `X`, `M` is of `Y` From 38966972f6a602cb1a855d674bae58197af14c77 Mon Sep 17 00:00:00 2001 From: Kelvin Lau Date: Sun, 11 Mar 2018 13:11:57 -0700 Subject: [PATCH 023/271] Few more updates to the edit graph. --- Myers Difference Algorithm/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Myers Difference Algorithm/README.md b/Myers Difference Algorithm/README.md index c1aa2da3a..6c242de88 100644 --- a/Myers Difference Algorithm/README.md +++ b/Myers Difference Algorithm/README.md @@ -19,7 +19,7 @@ MDA uses an **Edit Graph** to solve the LCS/SES problem. Below is a illustration -In this case, the arrays are: +The x-axis at the top of the graph represents one of the sequences, `X`. The y-axis at the left side of the graph represents the other sequence, `Y`. Hence, the two sequences in question is the following: ``` X = [A, B, C, A, B, B, A] From 3bf65574bf04db1e0540494ece247f2beba79a5c Mon Sep 17 00:00:00 2001 From: horita-yuya Date: Sat, 7 Apr 2018 03:30:09 +0900 Subject: [PATCH 024/271] add explanation --- Myers Difference Algorithm/README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Myers Difference Algorithm/README.md b/Myers Difference Algorithm/README.md index 6c242de88..e6137e8ce 100644 --- a/Myers Difference Algorithm/README.md +++ b/Myers Difference Algorithm/README.md @@ -34,6 +34,11 @@ MDA generates the edit graph through the following steps: 3. Check the points `(i, j)`, where `X[i] = Y[j]`, called match point, light green one. 4. Connect vertex `(i - 1, j - 1)` and vertex `(i, j)`, where `(i, j)` is match point, then diagonal edge appears. +Each elements on the figure shows that, +- `Red number and dotted lines`: The red number is the value of k and dotted lines are k-line. +- `Green dots: The match points`, which is the point `(i, j)` where `X[i] == Y[j]` +- `Blue line`: The shortest path from source to sink, which is the path we are going to find finally. + > **Note:** Here, the sequences' start index is 1 not 0, so `X[1] = A`, `Y[1] = C` We discuss about which path is the shortest from `source` to `sink`. Can move on the edges on the graph. I mean we can move on the grid, horizontal and vertical edges, and the diagonal edges. From a0cfcee54c015e1110ca7ab102d9ba84bda0ae85 Mon Sep 17 00:00:00 2001 From: Kelvin Lau Date: Sun, 22 Apr 2018 18:29:44 -0700 Subject: [PATCH 025/271] Update README.markdown --- Genetic/README.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Genetic/README.markdown b/Genetic/README.markdown index 07547c4b4..18afb9639 100644 --- a/Genetic/README.markdown +++ b/Genetic/README.markdown @@ -1,4 +1,4 @@ -individual# Genetic Algorthim +# Genetic Algorthim ## What is it? From 444b993d571d955b36aa0aa64cd03dd1a31761b3 Mon Sep 17 00:00:00 2001 From: Bill Barbour Date: Tue, 8 May 2018 15:24:10 -0400 Subject: [PATCH 026/271] Updated number to be prime; and Swift 4 update --- Rabin-Karp/Rabin-Karp.playground/Contents.swift | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Rabin-Karp/Rabin-Karp.playground/Contents.swift b/Rabin-Karp/Rabin-Karp.playground/Contents.swift index 739b74e2a..40cd176a6 100644 --- a/Rabin-Karp/Rabin-Karp.playground/Contents.swift +++ b/Rabin-Karp/Rabin-Karp.playground/Contents.swift @@ -8,7 +8,7 @@ print("Hello, Swift 4!") import UIKit struct Constants { - static let hashMultiplier = 69069 + static let hashMultiplier = 69061 } precedencegroup PowerPrecedence { higherThan: MultiplicationPrecedence } @@ -30,8 +30,8 @@ extension Character { // Find first position of pattern in the text using Rabin Karp algorithm public func search(text: String, pattern: String) -> Int { // convert to array of ints - let patternArray = pattern.flatMap { $0.asInt } - let textArray = text.flatMap { $0.asInt } + let patternArray = pattern.compactMap { $0.asInt } + let textArray = text.compactMap { $0.asInt } if textArray.count < patternArray.count { return -1 From 9b7ecd6a47e4522ae0b48ae4d938dc97a31f8a22 Mon Sep 17 00:00:00 2001 From: Ahmed Nader Date: Fri, 11 May 2018 23:23:20 +0200 Subject: [PATCH 027/271] Closest Pair of points algorithm --- .../ClosestPair.playground/Contents.swift | 224 ++++++++++++++++++ .../contents.xcplayground | 4 + .../contents.xcworkspacedata | 7 + .../xcshareddata/IDEWorkspaceChecks.plist | 8 + .../UserInterfaceState.xcuserstate | Bin 0 -> 10014 bytes .../Images/1200px-Closest_pair_of_points.png | Bin 0 -> 17683 bytes Closest Pair/Images/Case.png | Bin 0 -> 17660 bytes Closest Pair/Images/Strip.png | Bin 0 -> 18824 bytes Closest Pair/README.markdown | 88 +++++++ 9 files changed, 331 insertions(+) create mode 100644 Closest Pair/ClosestPair.playground/Contents.swift create mode 100644 Closest Pair/ClosestPair.playground/contents.xcplayground create mode 100644 Closest Pair/ClosestPair.playground/playground.xcworkspace/contents.xcworkspacedata create mode 100644 Closest Pair/ClosestPair.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist create mode 100644 Closest Pair/ClosestPair.playground/playground.xcworkspace/xcuserdata/admin.xcuserdatad/UserInterfaceState.xcuserstate create mode 100644 Closest Pair/Images/1200px-Closest_pair_of_points.png create mode 100644 Closest Pair/Images/Case.png create mode 100644 Closest Pair/Images/Strip.png create mode 100644 Closest Pair/README.markdown diff --git a/Closest Pair/ClosestPair.playground/Contents.swift b/Closest Pair/ClosestPair.playground/Contents.swift new file mode 100644 index 000000000..c11c1770b --- /dev/null +++ b/Closest Pair/ClosestPair.playground/Contents.swift @@ -0,0 +1,224 @@ +//Created by Ahmed Nader (github: AhmedNader42) on 4/4/18. + +func ClosestPairOf(points: [Point]) -> (minimum:Double, firstPoint:Point, secondPoint:Point) { + var innerPoints = mergeSort(points, sortAccording : true) + let result = ClosestPair(&innerPoints, innerPoints.count) + return (result.minValue, result.firstPoint, result.secondPoint) +} + +func ClosestPair(_ p : inout [Point],_ n : Int) -> (minValue: Double,firstPoint: Point,secondPoint: Point) +{ + // Brute force if only 3 points (To end recursion) + if n <= 3 + { + var i=0, j = i+1 + var minDist = Double.infinity + var newFirst:Point? = nil + var newSecond:Point? = nil + while i min { break } + if dist(strip[i], strip[x]) < temp + { + temp = dist(strip[i], strip[x]) + tempFirst = strip[i] + tempSecond = strip[x] + } + x+=1 + } + i+=1 + } + + if temp < min + { + min = temp; + first = tempFirst + second = tempSecond + } + return (min, first, second) +} + + + + +// MergeSort the array (Taken from Swift Algorithms Club with +// minor addition) +// sortAccodrding : true -> x, false -> y. +func mergeSort(_ array: [Point], sortAccording : Bool) -> [Point] { + guard array.count > 1 else { return array } + let middleIndex = array.count / 2 + let leftArray = mergeSort(Array(array[0.. [Point] { + + var compare : (Point, Point) -> Bool + + // Choose to compare with X or Y. + if sortAccording + { + compare = { p1,p2 in + return p1.x < p2.x + } + } + else + { + compare = { p1, p2 in + return p1.y < p2.y + } + } + + var leftIndex = 0 + var rightIndex = 0 + var orderedPile = [Point]() + if orderedPile.capacity < leftPile.count + rightPile.count { + orderedPile.reserveCapacity(leftPile.count + rightPile.count) + } + + while true { + guard leftIndex < leftPile.endIndex else { + orderedPile.append(contentsOf: rightPile[rightIndex.. Double +{ + let equation:Double = (((a.x-b.x)*(a.x-b.x))) + (((a.y-b.y)*(a.y-b.y))) + return equation.squareRoot() +} + + +var a = Point(0,2) +var b = Point(6,67) +var c = Point(43,71) +var d = Point(1000,1000) +var e = Point(39,107) +var f = Point(2000,2000) +var g = Point(3000,3000) +var h = Point(4000,4000) + + +var points = [a,b,c,d,e,f,g,h] +let endResult = ClosestPairOf(points: points) +print("Minimum Distance : \(endResult.minimum), The two points : (\(endResult.firstPoint.x ),\(endResult.firstPoint.y)), (\(endResult.secondPoint.x),\(endResult.secondPoint.y))") + diff --git a/Closest Pair/ClosestPair.playground/contents.xcplayground b/Closest Pair/ClosestPair.playground/contents.xcplayground new file mode 100644 index 000000000..a93d4844a --- /dev/null +++ b/Closest Pair/ClosestPair.playground/contents.xcplayground @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/Closest Pair/ClosestPair.playground/playground.xcworkspace/contents.xcworkspacedata b/Closest Pair/ClosestPair.playground/playground.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..919434a62 --- /dev/null +++ b/Closest Pair/ClosestPair.playground/playground.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/Closest Pair/ClosestPair.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Closest Pair/ClosestPair.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/Closest Pair/ClosestPair.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/Closest Pair/ClosestPair.playground/playground.xcworkspace/xcuserdata/admin.xcuserdatad/UserInterfaceState.xcuserstate b/Closest Pair/ClosestPair.playground/playground.xcworkspace/xcuserdata/admin.xcuserdatad/UserInterfaceState.xcuserstate new file mode 100644 index 0000000000000000000000000000000000000000..82b1303405d67c83db2a30dbba741c883e40fdff GIT binary patch literal 10014 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 A2LJ#7 literal 0 HcmV?d00001 diff --git a/Closest Pair/README.markdown b/Closest Pair/README.markdown new file mode 100644 index 000000000..57786c7ff --- /dev/null +++ b/Closest Pair/README.markdown @@ -0,0 +1,88 @@ +# ClosestPair + +Closest Pair is an algorithm that finds the closest pair of a given array of points By utilizing the Divide and Conquer methodology of solving problems so that it reaches the correct solution with O(nlogn) complexity. + +![Given points and we're required to find the two red ones](../Closest Pair/Images/1200px-Closest_pair_of_points.png) + +As we see in the above image there are an array of points and we need to find the closest two, But how do we do that without having to compare each two points which results in a whopping O(n^2) complexity? + +Here is the main algorithm (Steps) we'll follow. + +- Sort the array according to their position on the X-axis so that they are sorted in the array as they are naturally in math. + +```swift +var innerPoints = mergeSort(points, sortAccording : true) +``` + +- Divide the points into two arrays Left, Right and keep dividing until you reach to only having 3 points in your array. + +- The base case is you have less than 3 points compare those against each other (Brute force) then return the minimum distance you found and the two points. + +- Now we get the first observation in the below image, There could be 2 points both very close to each other and indeed those two are the closest pair but since our algorithm so far divides from the middle + +```swift +let line:Double = (p[mid].x + p[mid+1].x)/2 +``` + +and just recursively calls itself until it reaches the base case we don't detect those points. + +![ Points lying near the division line](../Closest Pair/Images/Case.png) + +- To solve this we start by sorting the array on the Y-axis to get the points in their natural order and then we start getting the difference between the X position of the point and the line we drew to divide and if it is less than the min we got so far from the recursion we add it to the strip + +```swift +var strip = [Point]() +var i=0, j = 0 +while i min { break } + if dist(strip[i], strip[x]) < temp + { + temp = dist(strip[i], strip[x]) + tempFirst = strip[i] + tempSecond = strip[x] + } + x+=1 + } + i+=1 + } +``` + +- Of course not every time you end up with the same shape but this is the worst case and it's rare to happen so in reality you end up with far less points valid for comparison and this is why the algorithm gets performance in addition to the sorting tricks we did. + +- Compare the points in the strip and if you find a smaller distance replace the current one with it. + + +So this is the rundown of how the algorithm works and you could see the fun little math tricks used to optimize this and we end up with O(nlogn) complexity mainly because of the sorting. + + +## See also + +See the playground to play around with the implementation of the algorithm + +[Wikipedia](https://en.wikipedia.org/wiki/Closest_pair_of_points_problem) + +*Written for Swift Algorithm Club by [Ahmed Nader](https://github.com/ahmednader42)* From 9b0a3c517d1e26ced6bd506b42af25bf2b99d287 Mon Sep 17 00:00:00 2001 From: Ahmed Nader Date: Fri, 11 May 2018 23:24:32 +0200 Subject: [PATCH 028/271] Images --- Closest Pair/README.markdown | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Closest Pair/README.markdown b/Closest Pair/README.markdown index 57786c7ff..35ea15653 100644 --- a/Closest Pair/README.markdown +++ b/Closest Pair/README.markdown @@ -2,7 +2,7 @@ Closest Pair is an algorithm that finds the closest pair of a given array of points By utilizing the Divide and Conquer methodology of solving problems so that it reaches the correct solution with O(nlogn) complexity. -![Given points and we're required to find the two red ones](../Closest Pair/Images/1200px-Closest_pair_of_points.png) +![Given points and we're required to find the two red ones](Closest Pair/Images/1200px-Closest_pair_of_points.png) As we see in the above image there are an array of points and we need to find the closest two, But how do we do that without having to compare each two points which results in a whopping O(n^2) complexity? @@ -26,7 +26,7 @@ let line:Double = (p[mid].x + p[mid+1].x)/2 and just recursively calls itself until it reaches the base case we don't detect those points. -![ Points lying near the division line](../Closest Pair/Images/Case.png) +![ Points lying near the division line](Closest Pair/Images/Case.png) - To solve this we start by sorting the array on the Y-axis to get the points in their natural order and then we start getting the difference between the X position of the point and the line we drew to divide and if it is less than the min we got so far from the recursion we add it to the strip @@ -46,7 +46,7 @@ while i Date: Fri, 11 May 2018 23:26:43 +0200 Subject: [PATCH 029/271] Update README.markdown --- Closest Pair/README.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Closest Pair/README.markdown b/Closest Pair/README.markdown index 35ea15653..3ce08dd49 100644 --- a/Closest Pair/README.markdown +++ b/Closest Pair/README.markdown @@ -2,7 +2,7 @@ Closest Pair is an algorithm that finds the closest pair of a given array of points By utilizing the Divide and Conquer methodology of solving problems so that it reaches the correct solution with O(nlogn) complexity. -![Given points and we're required to find the two red ones](Closest Pair/Images/1200px-Closest_pair_of_points.png) +![Given points and we're required to find the two red ones](../Closest\ Pair/Images/1200px-Closest_pair_of_points.png) As we see in the above image there are an array of points and we need to find the closest two, But how do we do that without having to compare each two points which results in a whopping O(n^2) complexity? From a018f72d59fd33a3990f343725dfd823f84a0340 Mon Sep 17 00:00:00 2001 From: Ahmed Nader Date: Fri, 11 May 2018 23:30:35 +0200 Subject: [PATCH 030/271] Update README.markdown --- Closest Pair/README.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Closest Pair/README.markdown b/Closest Pair/README.markdown index 3ce08dd49..5224bcef4 100644 --- a/Closest Pair/README.markdown +++ b/Closest Pair/README.markdown @@ -2,7 +2,7 @@ Closest Pair is an algorithm that finds the closest pair of a given array of points By utilizing the Divide and Conquer methodology of solving problems so that it reaches the correct solution with O(nlogn) complexity. -![Given points and we're required to find the two red ones](../Closest\ Pair/Images/1200px-Closest_pair_of_points.png) +![Given points and we're required to find the two red ones](../Images/1200px-Closest_pair_of_points.png) As we see in the above image there are an array of points and we need to find the closest two, But how do we do that without having to compare each two points which results in a whopping O(n^2) complexity? From 4174a840c332ee07f875306b098f710c0e3601bb Mon Sep 17 00:00:00 2001 From: Ahmed Nader Date: Fri, 11 May 2018 23:31:20 +0200 Subject: [PATCH 031/271] Update README.markdown --- Closest Pair/README.markdown | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Closest Pair/README.markdown b/Closest Pair/README.markdown index 5224bcef4..a4de4a28b 100644 --- a/Closest Pair/README.markdown +++ b/Closest Pair/README.markdown @@ -2,7 +2,7 @@ Closest Pair is an algorithm that finds the closest pair of a given array of points By utilizing the Divide and Conquer methodology of solving problems so that it reaches the correct solution with O(nlogn) complexity. -![Given points and we're required to find the two red ones](../Images/1200px-Closest_pair_of_points.png) +![Given points and we're required to find the two red ones](Images/1200px-Closest_pair_of_points.png) As we see in the above image there are an array of points and we need to find the closest two, But how do we do that without having to compare each two points which results in a whopping O(n^2) complexity? @@ -26,7 +26,7 @@ let line:Double = (p[mid].x + p[mid+1].x)/2 and just recursively calls itself until it reaches the base case we don't detect those points. -![ Points lying near the division line](Closest Pair/Images/Case.png) +![ Points lying near the division line](Images/Case.png) - To solve this we start by sorting the array on the Y-axis to get the points in their natural order and then we start getting the difference between the X position of the point and the line we drew to divide and if it is less than the min we got so far from the recursion we add it to the strip @@ -46,7 +46,7 @@ while i Date: Fri, 8 Jun 2018 01:47:25 -0700 Subject: [PATCH 032/271] Refactors first blurb. --- Myers Difference Algorithm/README.md | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/Myers Difference Algorithm/README.md b/Myers Difference Algorithm/README.md index e6137e8ce..6be30ecda 100644 --- a/Myers Difference Algorithm/README.md +++ b/Myers Difference Algorithm/README.md @@ -1,15 +1,13 @@ # Myers Difference Algorithm -Myers Difference Algorithm is an algorithm that finds a longest common subsequence(LCS) or shortest edit scripts(SES) of two sequences. MDA can accomplish this in O(ND) time, where N is the sum of the lengths of the two sequences. The common subsequence of two sequences is the sequence of elements that appear in the same order in both sequences. - -For example, let's assume you have two arrays: +Myers Difference Algorithm(MDA) is an algorithm that finds a longest common subsequence(LCS) or shortest edit scripts(SES) of two sequences. The common subsequence of two sequences is the sequence of elements that appear in the same order in both sequences. For example, let's assume you have two arrays: ``` -A = [1, 2, 3] -B = [2, 3, 4] +let firstArray = [1, 2, 3] +let secondArray = [2, 3, 4] ``` -The common subsequences of these two arrays are `[2]`, and `[2,3]`. The longest common sequence in this case is `[2,3]`. +The common subsequences of these two arrays are `[2]`, and `[2, 3]`. The longest common sequence in this case is `[2, 3]`. MDA can accomplish this in O(ND) time, where N is the sum of the lengths of the two sequences. ## Finding the length of the Longest Common Subsequence with Myers Algorithm on Edit Graph From 106b65ede0191fe7c6ba78fcd519334b7ea56e6a Mon Sep 17 00:00:00 2001 From: Julio Brazil Date: Mon, 1 Oct 2018 15:33:23 -0300 Subject: [PATCH 033/271] addition of Bubble sort algorithm --- .../MyPlayground.playground/Contents.swift | 27 ++++++++++++ .../Sources/BubbleSort.swift | 42 +++++++++++++++++++ .../contents.xcplayground | 4 ++ .../contents.xcworkspacedata | 7 ++++ .../xcshareddata/IDEWorkspaceChecks.plist | 8 ++++ .../xcshareddata/IDEWorkspaceChecks.plist | 8 ++++ 6 files changed, 96 insertions(+) create mode 100644 Bubble Sort/MyPlayground.playground/Contents.swift create mode 100644 Bubble Sort/MyPlayground.playground/Sources/BubbleSort.swift create mode 100644 Bubble Sort/MyPlayground.playground/contents.xcplayground create mode 100644 Bubble Sort/MyPlayground.playground/playground.xcworkspace/contents.xcworkspacedata create mode 100644 Bubble Sort/MyPlayground.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist create mode 100644 Bucket Sort/BucketSort.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist diff --git a/Bubble Sort/MyPlayground.playground/Contents.swift b/Bubble Sort/MyPlayground.playground/Contents.swift new file mode 100644 index 000000000..d0cf07ab3 --- /dev/null +++ b/Bubble Sort/MyPlayground.playground/Contents.swift @@ -0,0 +1,27 @@ +import Foundation + +public func BubbleSort (_ elements: [T]) -> [T] where T: Comparable { + var array = elements + + for i in 0.. (_ elements: [T]) -> [T] where T: Comparable { + var array = elements + + for i in 0.. + + + \ No newline at end of file diff --git a/Bubble Sort/MyPlayground.playground/playground.xcworkspace/contents.xcworkspacedata b/Bubble Sort/MyPlayground.playground/playground.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..919434a62 --- /dev/null +++ b/Bubble Sort/MyPlayground.playground/playground.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/Bubble Sort/MyPlayground.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Bubble Sort/MyPlayground.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/Bubble Sort/MyPlayground.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/Bucket Sort/BucketSort.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Bucket Sort/BucketSort.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/Bucket Sort/BucketSort.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + From 44711ad86d5fafc1f6db40bfebb5e94e277377b1 Mon Sep 17 00:00:00 2001 From: Julio Brazil Date: Mon, 1 Oct 2018 15:57:40 -0300 Subject: [PATCH 034/271] addition of convenience method --- .../SelectionSort.playground/Contents.swift | 1 + .../Sources/SelectionSort.swift | 26 +++++++++++++++++-- .../xcshareddata/IDEWorkspaceChecks.plist | 8 ++++++ 3 files changed, 33 insertions(+), 2 deletions(-) create mode 100644 Selection Sort/SelectionSort.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist diff --git a/Selection Sort/SelectionSort.playground/Contents.swift b/Selection Sort/SelectionSort.playground/Contents.swift index e0bfdf259..b16dadb8d 100644 --- a/Selection Sort/SelectionSort.playground/Contents.swift +++ b/Selection Sort/SelectionSort.playground/Contents.swift @@ -6,5 +6,6 @@ print("Hello, Swift 4!") #endif let list = [ 10, -1, 3, 9, 2, 27, 8, 5, 1, 3, 0, 26 ] +selectionSort(list) selectionSort(list, <) selectionSort(list, >) diff --git a/Selection Sort/SelectionSort.playground/Sources/SelectionSort.swift b/Selection Sort/SelectionSort.playground/Sources/SelectionSort.swift index 3015fde9b..b0bdfab55 100644 --- a/Selection Sort/SelectionSort.playground/Sources/SelectionSort.swift +++ b/Selection Sort/SelectionSort.playground/Sources/SelectionSort.swift @@ -1,4 +1,4 @@ -public func selectionSort(_ array: [T], _ isOrderedBefore: (T, T) -> Bool) -> [T] { +public func selectionSort(_ array: [T]) -> [T] { guard array.count > 1 else { return array } var a = array @@ -7,7 +7,7 @@ public func selectionSort(_ array: [T], _ isOrderedBefore: (T, T) // Find the lowest value in the rest of the array. var lowest = x for y in x + 1 ..< a.count { - if isOrderedBefore(a[y], a[lowest]) { + if a[y] < a[lowest] { lowest = y } } @@ -19,3 +19,25 @@ public func selectionSort(_ array: [T], _ isOrderedBefore: (T, T) } return a } + +public func selectionSort(_ array: [T], _ isLowerThan: (T, T) -> Bool) -> [T] { + guard array.count > 1 else { return array } + + var a = array + for x in 0 ..< a.count - 1 { + + // Find the lowest value in the rest of the array. + var lowest = x + for y in x + 1 ..< a.count { + if isLowerThan(a[y], a[lowest]) { + lowest = y + } + } + + // Swap the lowest value with the current array index. + if x != lowest { + a.swapAt(x, lowest) + } + } + return a +} diff --git a/Selection Sort/SelectionSort.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Selection Sort/SelectionSort.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/Selection Sort/SelectionSort.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + From d078c50bc281d92f0369fe3b6bac5508988e175a Mon Sep 17 00:00:00 2001 From: Julio Brazil Date: Mon, 1 Oct 2018 16:02:04 -0300 Subject: [PATCH 035/271] addition of function description --- .../Sources/SelectionSort.swift | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/Selection Sort/SelectionSort.playground/Sources/SelectionSort.swift b/Selection Sort/SelectionSort.playground/Sources/SelectionSort.swift index b0bdfab55..3a27ef9dd 100644 --- a/Selection Sort/SelectionSort.playground/Sources/SelectionSort.swift +++ b/Selection Sort/SelectionSort.playground/Sources/SelectionSort.swift @@ -1,3 +1,7 @@ +/// Performs the Selection sort algorithm on a array +/// +/// - Parameter array: array of elements that conform to the Comparable protocol +/// - Returns: an array in ascending order public func selectionSort(_ array: [T]) -> [T] { guard array.count > 1 else { return array } @@ -20,6 +24,12 @@ public func selectionSort(_ array: [T]) -> [T] { return a } +/// Performs the Selection sort algorithm on a array using the provided comparisson method +/// +/// - Parameters: +/// - array: array of elements that conform to the Comparable protocol +/// - isLowerThan: returns true if the two provided elements are in the correct order +/// - Returns: a sorted array public func selectionSort(_ array: [T], _ isLowerThan: (T, T) -> Bool) -> [T] { guard array.count > 1 else { return array } From a9b6c5f68e9d7ac0989e6f42c0bd98265740bc36 Mon Sep 17 00:00:00 2001 From: Julio Brazil Date: Tue, 2 Oct 2018 11:49:32 -0300 Subject: [PATCH 036/271] correction in the algorithm --- .../MyPlayground.playground/Contents.swift | 16 ++++++---------- .../Sources/BubbleSort.swift | 8 ++++---- 2 files changed, 10 insertions(+), 14 deletions(-) diff --git a/Bubble Sort/MyPlayground.playground/Contents.swift b/Bubble Sort/MyPlayground.playground/Contents.swift index d0cf07ab3..16466e0bc 100644 --- a/Bubble Sort/MyPlayground.playground/Contents.swift +++ b/Bubble Sort/MyPlayground.playground/Contents.swift @@ -4,10 +4,11 @@ public func BubbleSort (_ elements: [T]) -> [T] where T: Comparable { var array = elements for i in 0.. (_ elements: [T]) -> [T] where T: Comparable { return array } - -var array = [Int]() - -for _ in 0...10 { - array.append(Int.random(in: 0...500)) -} +var array = [4,2,1,3] print("before:",array) print("after:",BubbleSort(array)) diff --git a/Bubble Sort/MyPlayground.playground/Sources/BubbleSort.swift b/Bubble Sort/MyPlayground.playground/Sources/BubbleSort.swift index 8f1ec80f8..5ce18ef9b 100644 --- a/Bubble Sort/MyPlayground.playground/Sources/BubbleSort.swift +++ b/Bubble Sort/MyPlayground.playground/Sources/BubbleSort.swift @@ -29,10 +29,10 @@ public func BubbleSort (_ elements: [T]) -> [T] where T: Comparable { var array = elements for i in 0.. Date: Tue, 2 Oct 2018 13:36:20 -0300 Subject: [PATCH 037/271] added imlementation information on readme --- Bubble Sort/README.markdown | 72 ++++++++++++++++++++++++++++++++++++- 1 file changed, 71 insertions(+), 1 deletion(-) diff --git a/Bubble Sort/README.markdown b/Bubble Sort/README.markdown index 93d370827..80161ce56 100644 --- a/Bubble Sort/README.markdown +++ b/Bubble Sort/README.markdown @@ -1,6 +1,6 @@ # Bubble Sort -Bubble sort is a sorting algorithm that is implemented by starting in the beginning of the array and swapping the first two elements only if the first element is greater than the second element. This comparison is then moved onto the next pair and so on and so forth. This is done until the array is completely sorted. The smaller items slowly “bubble” up to the beginning of the array. +Bubble sort is a sorting algorithm that is implemented by starting in the beginning of the array and swapping the first two elements only if the first element is greater than the second element. This comparison is then moved onto the next pair and so on and so forth. This is done until the array is completely sorted. The smaller items slowly “bubble” up to the beginning of the array.Sometimes this algorithm is refered as Sinking sort, due to the larger, or heavier elements sinking to the end of the array. ##### Runtime: - Average: O(N^2) @@ -12,3 +12,73 @@ Bubble sort is a sorting algorithm that is implemented by starting in the beginn ### Implementation: The implementation will not be shown as the average and worst runtimes show that this is a very inefficient algorithm. However, having a grasp of the concept will help you understand the basics of simple sorting algorithms. + +Bubble sort is a very simple sorting algorithm, it consists in comparing pairs of adjacent elements in the array, if the first element is larger, swap them, otherwise, you do nothing and go for the next comparison. +This is accomplished by looking through the array `n` times, `n` being the amount of elements in the array. + +#### Example +Let us take the array `[5, 1, 4, 2, 8]`, and sort the array from lowest number to greatest number using bubble sort. In each step, elements written in bold are being compared. Three passes will be required. + +##### First Pass +[ **5 1** 4 2 8 ] -> [ **1 5** 4 2 8 ], Here, algorithm compares the first two elements, and swaps since 5 > 1. + +[ 1 **5 4** 2 8 ] -> [ 1 **4 5** 2 8 ], Swap since 5 > 4 + +[ 1 4 **5 2** 8 ] -> [ 1 4 **2 5** 8 ], Swap since 5 > 2 + +[ 1 4 2 **5 8** ] -> [ 1 4 2 **5 8** ], Now, since these elements are already in order (8 > 5), algorithm does not swap them. + +##### Second Pass +[ **1 4** 2 5 8 ] -> [ **1 4** 2 5 8 ] + +[ 1 **4 2** 5 8 ] -> [ 1 **2 4** 5 8 ], Swap since 4 > 2 + +[ 1 2 **4 5** 8 ] -> [ 1 2 **4 5** 8 ] + +[ 1 2 4 **5 8** ] -> [ 1 2 4 **5 8** ] +Now, the array is already sorted, but the algorithm does not know if it is completed. The algorithm needs one whole pass without any swap to know it is sorted. + +##### Third Pass +[ **1 2** 4 5 8 ] -> [ **1 2** 4 5 8 ] + +[ 1 **2 4** 5 8 ] -> [ 1 **2 4** 5 8 ] + +[ 1 2 **4 5** 8 ] -> [ 1 2 **4 5** 8 ] + +[ 1 2 4 **5 8** ] -> [ 1 2 4 **5 8** ] + +This is the same for the forth and fifth passes. + +#### Code +```swift +for i in 0.. Date: Thu, 4 Oct 2018 22:07:39 +0530 Subject: [PATCH 038/271] Swift 4.2 [Array2D] --- Array2D/Array2D.playground/Contents.swift | 5 ----- Array2D/Tests/Tests.xcodeproj/project.pbxproj | 4 ++-- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/Array2D/Array2D.playground/Contents.swift b/Array2D/Array2D.playground/Contents.swift index 77c0b364c..d31d77540 100644 --- a/Array2D/Array2D.playground/Contents.swift +++ b/Array2D/Array2D.playground/Contents.swift @@ -1,8 +1,3 @@ -// last checked with Xcode 9.0b4 -#if swift(>=4.0) -print("Hello, Swift 4!") -#endif - /* Two-dimensional array with a fixed number of rows and columns. This is mostly handy for games that are played on a grid, such as chess. diff --git a/Array2D/Tests/Tests.xcodeproj/project.pbxproj b/Array2D/Tests/Tests.xcodeproj/project.pbxproj index a0fb1480b..af9b7c3b8 100644 --- a/Array2D/Tests/Tests.xcodeproj/project.pbxproj +++ b/Array2D/Tests/Tests.xcodeproj/project.pbxproj @@ -226,7 +226,7 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = swift.algorithm.club.Tests; PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 3.0; + SWIFT_VERSION = 4.2; }; name = Debug; }; @@ -238,7 +238,7 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = swift.algorithm.club.Tests; PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 3.0; + SWIFT_VERSION = 4.2; }; name = Release; }; From c7d17128ccda1f80da11e85e5a381102e1fab8c6 Mon Sep 17 00:00:00 2001 From: Ashish Kakkad Date: Thu, 4 Oct 2018 22:51:29 +0530 Subject: [PATCH 039/271] [Swift 4.2] Graph --- Graph/Graph.playground/Contents.swift | 6 ------ Graph/Graph.playground/timeline.xctimeline | 2 +- Graph/Graph.xcodeproj/project.pbxproj | 14 +++++++++----- .../xcshareddata/xcschemes/Graph.xcscheme | 2 +- .../xcshareddata/xcschemes/GraphTests.xcscheme | 2 +- Graph/GraphTests/GraphTests.swift | 7 ------- 6 files changed, 12 insertions(+), 21 deletions(-) diff --git a/Graph/Graph.playground/Contents.swift b/Graph/Graph.playground/Contents.swift index 0410942f8..fde396e64 100644 --- a/Graph/Graph.playground/Contents.swift +++ b/Graph/Graph.playground/Contents.swift @@ -1,11 +1,5 @@ import Graph -// last checked with Xcode 9.0b4 -#if swift(>=4.0) -print("Hello, Swift 4!") -#endif - - for graph in [AdjacencyMatrixGraph(), AdjacencyListGraph()] { let v1 = graph.createVertex(1) diff --git a/Graph/Graph.playground/timeline.xctimeline b/Graph/Graph.playground/timeline.xctimeline index 6afe06b6f..59717856a 100644 --- a/Graph/Graph.playground/timeline.xctimeline +++ b/Graph/Graph.playground/timeline.xctimeline @@ -3,7 +3,7 @@ version = "3.0"> diff --git a/Graph/Graph.xcodeproj/project.pbxproj b/Graph/Graph.xcodeproj/project.pbxproj index 17a5a7d6b..790f6ac18 100644 --- a/Graph/Graph.xcodeproj/project.pbxproj +++ b/Graph/Graph.xcodeproj/project.pbxproj @@ -158,7 +158,7 @@ isa = PBXProject; attributes = { LastSwiftUpdateCheck = 0730; - LastUpgradeCheck = 0900; + LastUpgradeCheck = 1000; ORGANIZATIONNAME = "Swift Algorithm Club"; TargetAttributes = { 49BFA2FC1CDF886B00522D66 = { @@ -251,12 +251,14 @@ CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; @@ -289,7 +291,7 @@ ONLY_ACTIVE_ARCH = YES; SDKROOT = macosx; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 4.0; + SWIFT_VERSION = 4.2; VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; }; @@ -308,12 +310,14 @@ CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; @@ -339,7 +343,7 @@ MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = macosx; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; - SWIFT_VERSION = 4.0; + SWIFT_VERSION = 4.2; VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; }; @@ -364,7 +368,7 @@ SKIP_INSTALL = YES; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_SWIFT3_OBJC_INFERENCE = Off; - SWIFT_VERSION = 4.0; + SWIFT_VERSION = 4.2; }; name = Debug; }; @@ -386,7 +390,7 @@ PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; SWIFT_SWIFT3_OBJC_INFERENCE = Off; - SWIFT_VERSION = 4.0; + SWIFT_VERSION = 4.2; }; name = Release; }; diff --git a/Graph/Graph.xcodeproj/xcshareddata/xcschemes/Graph.xcscheme b/Graph/Graph.xcodeproj/xcshareddata/xcschemes/Graph.xcscheme index a12d85dad..73524effc 100644 --- a/Graph/Graph.xcodeproj/xcshareddata/xcschemes/Graph.xcscheme +++ b/Graph/Graph.xcodeproj/xcshareddata/xcschemes/Graph.xcscheme @@ -1,6 +1,6 @@ =4.0) - print("Hello, Swift 4!") - #endif - } - func testAdjacencyMatrixGraphDescription() { let graph = AdjacencyMatrixGraph() From 7442c10f596fec191eacbec644fcf8d5fae7f30a Mon Sep 17 00:00:00 2001 From: Vyacheslav Khorkov Date: Thu, 4 Oct 2018 22:34:48 +0500 Subject: [PATCH 040/271] Update Z-Algorithm up to Swift 4.2. --- Z-Algorithm/README.markdown | 5 ++--- Z-Algorithm/ZAlgorithm.swift | 3 +-- Z-Algorithm/ZetaAlgorithm.playground/Contents.swift | 10 ++-------- Z-Algorithm/ZetaAlgorithm.swift | 2 +- 4 files changed, 6 insertions(+), 14 deletions(-) diff --git a/Z-Algorithm/README.markdown b/Z-Algorithm/README.markdown index 8b84c28bf..a6423be03 100644 --- a/Z-Algorithm/README.markdown +++ b/Z-Algorithm/README.markdown @@ -28,8 +28,7 @@ This a simple description of the idea that is behind this algorithm. There are a Here is the code of the function that computes the Z-array: ```swift func ZetaAlgorithm(ptrn: String) -> [Int]? { - - let pattern = Array(ptrn.characters) + let pattern = Array(ptrn) let patternLength: Int = pattern.count guard patternLength > 0 else { @@ -131,7 +130,7 @@ The Z-Algorithm discussed above leads to the simplest linear-time string matchin extension String { func indexesOf(pattern: String) -> [Int]? { - let patternLength: Int = pattern.characters.count + let patternLength: Int = pattern.count /* Let's calculate the Z-Algorithm on the concatenation of pattern and text */ let zeta = ZetaAlgorithm(ptrn: pattern + "💲" + self) diff --git a/Z-Algorithm/ZAlgorithm.swift b/Z-Algorithm/ZAlgorithm.swift index 969a3599b..65acaabd1 100644 --- a/Z-Algorithm/ZAlgorithm.swift +++ b/Z-Algorithm/ZAlgorithm.swift @@ -9,8 +9,7 @@ import Foundation func ZetaAlgorithm(ptrn: String) -> [Int]? { - - let pattern = Array(ptrn.characters) + let pattern = Array(ptrn) let patternLength = pattern.count guard patternLength > 0 else { diff --git a/Z-Algorithm/ZetaAlgorithm.playground/Contents.swift b/Z-Algorithm/ZetaAlgorithm.playground/Contents.swift index d057080a1..56aa92170 100644 --- a/Z-Algorithm/ZetaAlgorithm.playground/Contents.swift +++ b/Z-Algorithm/ZetaAlgorithm.playground/Contents.swift @@ -1,13 +1,7 @@ //: Playground - noun: a place where people can play -// last checked with Xcode 9.0b4 -#if swift(>=4.0) -print("Hello, Swift 4!") -#endif - func ZetaAlgorithm(ptrn: String) -> [Int]? { - - let pattern = Array(ptrn.characters) + let pattern = Array(ptrn) let patternLength = pattern.count guard patternLength > 0 else { @@ -65,7 +59,7 @@ func ZetaAlgorithm(ptrn: String) -> [Int]? { extension String { func indexesOf(pattern: String) -> [Int]? { - let patternLength = pattern.characters.count + let patternLength = pattern.count let zeta = ZetaAlgorithm(ptrn: pattern + "💲" + self) guard zeta != nil else { diff --git a/Z-Algorithm/ZetaAlgorithm.swift b/Z-Algorithm/ZetaAlgorithm.swift index e60c1617f..f2c453364 100644 --- a/Z-Algorithm/ZetaAlgorithm.swift +++ b/Z-Algorithm/ZetaAlgorithm.swift @@ -11,7 +11,7 @@ import Foundation extension String { func indexesOf(pattern: String) -> [Int]? { - let patternLength = pattern.characters.count + let patternLength = pattern.count let zeta = ZetaAlgorithm(ptrn: pattern + "💲" + self) guard zeta != nil else { From 3c3168ea6e8d01972727d8db5ebea10f4aa794d3 Mon Sep 17 00:00:00 2001 From: Vyacheslav Khorkov Date: Thu, 4 Oct 2018 23:13:45 +0500 Subject: [PATCH 041/271] Update Deque up to Swift 4.2. --- Deque/Deque-Simple.swift | 2 +- Deque/Deque.playground/Contents.swift | 5 ----- Deque/README.markdown | 2 +- 3 files changed, 2 insertions(+), 7 deletions(-) diff --git a/Deque/Deque-Simple.swift b/Deque/Deque-Simple.swift index f4f5f0409..fc0fcb2b2 100644 --- a/Deque/Deque-Simple.swift +++ b/Deque/Deque-Simple.swift @@ -21,7 +21,7 @@ public struct Deque { } public mutating func enqueueFront(_ element: T) { - array.insert(element, atIndex: 0) + array.insert(element, at: 0) } public mutating func dequeue() -> T? { diff --git a/Deque/Deque.playground/Contents.swift b/Deque/Deque.playground/Contents.swift index df9b57a5e..9e7b22c02 100644 --- a/Deque/Deque.playground/Contents.swift +++ b/Deque/Deque.playground/Contents.swift @@ -1,10 +1,5 @@ //: Playground - noun: a place where people can play -// last checked with Xcode 9.0b4 -#if swift(>=4.0) -print("Hello, Swift 4!") -#endif - public struct Deque { private var array = [T]() diff --git a/Deque/README.markdown b/Deque/README.markdown index fda1de5f8..f3172e16e 100644 --- a/Deque/README.markdown +++ b/Deque/README.markdown @@ -23,7 +23,7 @@ public struct Deque { } public mutating func enqueueFront(_ element: T) { - array.insert(element, atIndex: 0) + array.insert(element, at: 0) } public mutating func dequeue() -> T? { From ed155f211d5b98fc54e3de40b55680367b5e1e93 Mon Sep 17 00:00:00 2001 From: Vyacheslav Khorkov Date: Thu, 4 Oct 2018 23:21:00 +0500 Subject: [PATCH 042/271] Remove notice from GCD playground. --- GCD/GCD.playground/Contents.swift | 5 ----- 1 file changed, 5 deletions(-) diff --git a/GCD/GCD.playground/Contents.swift b/GCD/GCD.playground/Contents.swift index f0fceb0da..c44f28310 100644 --- a/GCD/GCD.playground/Contents.swift +++ b/GCD/GCD.playground/Contents.swift @@ -1,10 +1,5 @@ //: Playground - noun: a place where people can play -// last checked with Xcode 9.0b4 -#if swift(>=4.0) -print("Hello, Swift 4!") -#endif - // Recursive version func gcd(_ a: Int, _ b: Int) -> Int { let r = a % b From 945c7cbe8e6f79dd31f4e0f3468d22d0f5f024c2 Mon Sep 17 00:00:00 2001 From: Vyacheslav Khorkov Date: Thu, 4 Oct 2018 23:28:36 +0500 Subject: [PATCH 043/271] Remove notice from FixedSizeArray playground. --- Fixed Size Array/FixedSizeArray.playground/Contents.swift | 5 ----- 1 file changed, 5 deletions(-) diff --git a/Fixed Size Array/FixedSizeArray.playground/Contents.swift b/Fixed Size Array/FixedSizeArray.playground/Contents.swift index 8b5bc1147..616f8443d 100644 --- a/Fixed Size Array/FixedSizeArray.playground/Contents.swift +++ b/Fixed Size Array/FixedSizeArray.playground/Contents.swift @@ -1,10 +1,5 @@ //: Playground - noun: a place where people can play -// last checked with Xcode 9.0b4 -#if swift(>=4.0) - print("Hello, Swift 4!") -#endif - /* An unordered array with a maximum size. From 8ea8a6590457b2ba931444ea75506e329850e788 Mon Sep 17 00:00:00 2001 From: Vyacheslav Khorkov Date: Thu, 4 Oct 2018 23:34:40 +0500 Subject: [PATCH 044/271] Update Insertion Sort up to Swift 4.2. --- .../InsertionSort.playground/Contents.swift | 5 ---- .../Tests/Tests.xcodeproj/project.pbxproj | 26 ++++++++++++++++--- .../xcshareddata/xcschemes/Tests.xcscheme | 2 +- 3 files changed, 23 insertions(+), 10 deletions(-) diff --git a/Insertion Sort/InsertionSort.playground/Contents.swift b/Insertion Sort/InsertionSort.playground/Contents.swift index 9a10ec04a..184fc36e4 100644 --- a/Insertion Sort/InsertionSort.playground/Contents.swift +++ b/Insertion Sort/InsertionSort.playground/Contents.swift @@ -1,10 +1,5 @@ //: Playground - noun: a place where people can play -// last checked with Xcode 9.0b4 -#if swift(>=4.0) -print("Hello, Swift 4!") -#endif - /// Performs the Insertion sort algorithm to a given array /// /// - Parameters: diff --git a/Insertion Sort/Tests/Tests.xcodeproj/project.pbxproj b/Insertion Sort/Tests/Tests.xcodeproj/project.pbxproj index ee3ca1cae..e9ea3bc53 100644 --- a/Insertion Sort/Tests/Tests.xcodeproj/project.pbxproj +++ b/Insertion Sort/Tests/Tests.xcodeproj/project.pbxproj @@ -86,12 +86,12 @@ isa = PBXProject; attributes = { LastSwiftUpdateCheck = 0720; - LastUpgradeCheck = 0800; + LastUpgradeCheck = 1000; ORGANIZATIONNAME = "Swift Algorithm Club"; TargetAttributes = { 7B2BBC7F1C779D720067B71D = { CreatedOnToolsVersion = 7.2; - LastSwiftMigration = 0800; + LastSwiftMigration = 1000; }; }; }; @@ -145,14 +145,22 @@ CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; @@ -191,14 +199,22 @@ CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; @@ -230,7 +246,8 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = swift.algorithm.club.Tests; PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 3.0; + SWIFT_SWIFT3_OBJC_INFERENCE = On; + SWIFT_VERSION = 4.2; }; name = Debug; }; @@ -242,7 +259,8 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = swift.algorithm.club.Tests; PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 3.0; + SWIFT_SWIFT3_OBJC_INFERENCE = On; + SWIFT_VERSION = 4.2; }; name = Release; }; diff --git a/Insertion Sort/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme b/Insertion Sort/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme index 14f27f777..afd69e6a7 100644 --- a/Insertion Sort/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme +++ b/Insertion Sort/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme @@ -1,6 +1,6 @@ Date: Thu, 4 Oct 2018 20:49:35 +0200 Subject: [PATCH 045/271] Update project with Xcode 10. --- .../Tests/Tests.xcodeproj/project.pbxproj | 24 +++++++++++++++---- .../xcshareddata/IDEWorkspaceChecks.plist | 8 +++++++ .../xcshareddata/xcschemes/Tests.xcscheme | 2 +- 3 files changed, 29 insertions(+), 5 deletions(-) create mode 100644 Bloom Filter/Tests/Tests.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist diff --git a/Bloom Filter/Tests/Tests.xcodeproj/project.pbxproj b/Bloom Filter/Tests/Tests.xcodeproj/project.pbxproj index 6493fd153..f0649ba26 100644 --- a/Bloom Filter/Tests/Tests.xcodeproj/project.pbxproj +++ b/Bloom Filter/Tests/Tests.xcodeproj/project.pbxproj @@ -83,12 +83,12 @@ isa = PBXProject; attributes = { LastSwiftUpdateCheck = 0720; - LastUpgradeCheck = 0800; + LastUpgradeCheck = 1000; ORGANIZATIONNAME = "Swift Algorithm Club"; TargetAttributes = { 7B2BBC7F1C779D720067B71D = { CreatedOnToolsVersion = 7.2; - LastSwiftMigration = 0800; + LastSwiftMigration = 1000; }; }; }; @@ -141,14 +141,22 @@ CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; @@ -188,14 +196,22 @@ CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; @@ -228,7 +244,7 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = swift.algorithm.club.Tests; PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 4.0; + SWIFT_VERSION = 4.2; }; name = Debug; }; @@ -240,7 +256,7 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = swift.algorithm.club.Tests; PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 4.0; + SWIFT_VERSION = 4.2; }; name = Release; }; diff --git a/Bloom Filter/Tests/Tests.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Bloom Filter/Tests/Tests.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/Bloom Filter/Tests/Tests.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/Bloom Filter/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme b/Bloom Filter/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme index 14f27f777..afd69e6a7 100644 --- a/Bloom Filter/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme +++ b/Bloom Filter/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme @@ -1,6 +1,6 @@ Date: Thu, 4 Oct 2018 20:50:05 +0200 Subject: [PATCH 046/271] Remove use of deprecated `characters` property. --- Bloom Filter/Tests/BloomFilterTests.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Bloom Filter/Tests/BloomFilterTests.swift b/Bloom Filter/Tests/BloomFilterTests.swift index 30df702a7..d88ec0a31 100644 --- a/Bloom Filter/Tests/BloomFilterTests.swift +++ b/Bloom Filter/Tests/BloomFilterTests.swift @@ -6,7 +6,7 @@ import XCTest func djb2(_ x: String) -> Int { var hash = 5381 - for char in x.characters { + for char in x { hash = ((hash << 5) &+ hash) &+ char.hashValue } @@ -16,7 +16,7 @@ func djb2(_ x: String) -> Int { func sdbm(_ x: String) -> Int { var hash = 0 - for char in x.characters { + for char in x { hash = char.hashValue &+ (hash << 6) &+ (hash << 16) &- hash } From 6ef7a6e6ad07781320418d276a67eaa4e3d635d7 Mon Sep 17 00:00:00 2001 From: Bruno Scheele Date: Thu, 4 Oct 2018 20:57:46 +0200 Subject: [PATCH 047/271] Xcode 10 automated changes. --- .../xcshareddata/IDEWorkspaceChecks.plist | 8 ++++++++ Bloom Filter/BloomFilter.playground/timeline.xctimeline | 6 ------ 2 files changed, 8 insertions(+), 6 deletions(-) create mode 100644 Bloom Filter/BloomFilter.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist delete mode 100644 Bloom Filter/BloomFilter.playground/timeline.xctimeline diff --git a/Bloom Filter/BloomFilter.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Bloom Filter/BloomFilter.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/Bloom Filter/BloomFilter.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/Bloom Filter/BloomFilter.playground/timeline.xctimeline b/Bloom Filter/BloomFilter.playground/timeline.xctimeline deleted file mode 100644 index bf468afec..000000000 --- a/Bloom Filter/BloomFilter.playground/timeline.xctimeline +++ /dev/null @@ -1,6 +0,0 @@ - - - - - From 4201fb4fc8bfefe4ab9651f5c393c55ddfd5f294 Mon Sep 17 00:00:00 2001 From: Bruno Scheele Date: Thu, 4 Oct 2018 20:58:26 +0200 Subject: [PATCH 048/271] Update for Swift 4.2. * Remove the top code snippet, as per instructions. * Remove use of deprecated `characters` property. --- Bloom Filter/BloomFilter.playground/Contents.swift | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/Bloom Filter/BloomFilter.playground/Contents.swift b/Bloom Filter/BloomFilter.playground/Contents.swift index 9e4a89351..7a3719d57 100644 --- a/Bloom Filter/BloomFilter.playground/Contents.swift +++ b/Bloom Filter/BloomFilter.playground/Contents.swift @@ -1,8 +1,5 @@ //: Playground - noun: a place where people can play -// last checked with Xcode 9.0b4 -#if swift(>=4.0) -print("Hello, Swift 4!") -#endif + public class BloomFilter { fileprivate var array: [Bool] private var hashFunctions: [(T) -> Int] @@ -54,7 +51,7 @@ public class BloomFilter { func djb2(x: String) -> Int { var hash = 5381 - for char in x.characters { + for char in x { hash = ((hash << 5) &+ hash) &+ char.hashValue } return Int(hash) @@ -62,7 +59,7 @@ func djb2(x: String) -> Int { func sdbm(x: String) -> Int { var hash = 0 - for char in x.characters { + for char in x { hash = char.hashValue &+ (hash << 6) &+ (hash << 16) &- hash } return Int(hash) From 849309c5eb5d2ef29918940536cc1b011b665b3c Mon Sep 17 00:00:00 2001 From: Bruno Scheele Date: Thu, 4 Oct 2018 21:45:50 +0200 Subject: [PATCH 049/271] Add note about Hasher in README. * Adds a section about another Bloom filter approach, using only a single hashing function with Swift 4.2's `Hasher`. * Adds links to some more documentation and a blog post implementing the Bloom filter in this way. * Adds my name as updater. --- Bloom Filter/README.markdown | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/Bloom Filter/README.markdown b/Bloom Filter/README.markdown index 3fff0a379..4364db857 100644 --- a/Bloom Filter/README.markdown +++ b/Bloom Filter/README.markdown @@ -100,4 +100,29 @@ public func query(_ value: T) -> Bool { If you're coming from another imperative language, you might notice the unusual syntax in the `exists` assignment. Swift makes use of functional paradigms when it makes code more consise and readable, and in this case `reduce` is a much more consise way to check if all the required bits are `true` than a `for` loop. -*Written for Swift Algorithm Club by Jamil Dhanani. Edited by Matthijs Hollemans.* +## Another approach + +Another approach to create different hashes of an element for use in the Bloom filter, is to use the same hash function for every iteration, but combine it with different random numbers. This can help, because finding good hashing functions is hard, but combining them is equally non-trivial. + +``` +hash("Hello world!") >> hash(987654321) // would flip bit 8 +hash("Hello world!") >> hash(123456789) // would flip bit 2 +``` + +Since Swift 4.2, `Hasher` is now included in the Standard library, which is designed to reduce multiple hashes to a single hash in an efficient manner. This makes combining the hashes trivial. + +``` +private func computeHashes(_ value: T) -> [Int] { + return randomSeeds.map() { seed in + let hasher = Hasher() + hasher.combine(seed) + hasher.combine(value) + let hashValue = hasher.finalize() + return abs(hashValue % array.count) + } +} +``` + +If you want to learn more about this approach, you can read about the [Hasher documentation](https://developer.apple.com/documentation/swift/hasher) or Soroush Khanlou's [Swift 4.2 Bloom filter](http://khanlou.com/2018/09/bloom-filters/) implementation. + +*Written for Swift Algorithm Club by Jamil Dhanani. Edited by Matthijs Hollemans. Updated by Bruno Scheele.* From a56b88370d49aaf0d5640ca59d955f61178108f8 Mon Sep 17 00:00:00 2001 From: KelCodesStuff Date: Thu, 4 Oct 2018 21:33:32 -0400 Subject: [PATCH 050/271] [Swift 4.2] Update Binary Search Tree --- .../Contents.swift | 5 -- .../xcshareddata/IDEWorkspaceChecks.plist | 8 +++ .../Tests/Tests.xcodeproj/project.pbxproj | 47 ++++++++++++++--- .../xcshareddata/IDEWorkspaceChecks.plist | 8 +++ .../xcshareddata/xcschemes/Tests.xcscheme | 2 +- .../Contents.swift | 5 -- .../xcshareddata/IDEWorkspaceChecks.plist | 8 +++ .../Sources/BinarySearch.swift | 52 ------------------- .../contents.xcworkspacedata | 7 --- 9 files changed, 64 insertions(+), 78 deletions(-) create mode 100644 Binary Search Tree/Solution 1/BinarySearchTree.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist create mode 100644 Binary Search Tree/Solution 1/Tests/Tests.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist create mode 100644 Binary Search Tree/Solution 2/BinarySearchTree.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist delete mode 100644 Binary Search/BinarySearch.playground/Sources/BinarySearch.swift delete mode 100644 Binary Search/BinarySearch.playground/playground.xcworkspace/contents.xcworkspacedata diff --git a/Binary Search Tree/Solution 1/BinarySearchTree.playground/Contents.swift b/Binary Search Tree/Solution 1/BinarySearchTree.playground/Contents.swift index 8c06ae9e1..ec9902283 100644 --- a/Binary Search Tree/Solution 1/BinarySearchTree.playground/Contents.swift +++ b/Binary Search Tree/Solution 1/BinarySearchTree.playground/Contents.swift @@ -1,10 +1,5 @@ //: Playground - noun: a place where people can play -// last checked with Xcode 9.0b4 -#if swift(>=4.0) -print("Hello, Swift 4!") -#endif - let tree = BinarySearchTree(value: 7) tree.insert(value: 2) tree.insert(value: 5) diff --git a/Binary Search Tree/Solution 1/BinarySearchTree.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Binary Search Tree/Solution 1/BinarySearchTree.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/Binary Search Tree/Solution 1/BinarySearchTree.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/Binary Search Tree/Solution 1/Tests/Tests.xcodeproj/project.pbxproj b/Binary Search Tree/Solution 1/Tests/Tests.xcodeproj/project.pbxproj index f4c3f65c7..ff594fff8 100644 --- a/Binary Search Tree/Solution 1/Tests/Tests.xcodeproj/project.pbxproj +++ b/Binary Search Tree/Solution 1/Tests/Tests.xcodeproj/project.pbxproj @@ -3,7 +3,7 @@ archiveVersion = 1; classes = { }; - objectVersion = 46; + objectVersion = 51; objects = { /* Begin PBXBuildFile section */ @@ -83,17 +83,17 @@ isa = PBXProject; attributes = { LastSwiftUpdateCheck = 0720; - LastUpgradeCheck = 0720; + LastUpgradeCheck = 1000; ORGANIZATIONNAME = "Swift Algorithm Club"; TargetAttributes = { 7B2BBC7F1C779D720067B71D = { CreatedOnToolsVersion = 7.2; - LastSwiftMigration = 0820; + LastSwiftMigration = 1000; }; }; }; buildConfigurationList = 7B2BBC6C1C779D710067B71D /* Build configuration list for PBXProject "Tests" */; - compatibilityVersion = "Xcode 3.2"; + compatibilityVersion = "Xcode 10.0"; developmentRegion = English; hasScannedForEncodings = 0; knownRegions = ( @@ -141,13 +141,23 @@ CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_IDENTITY = "-"; @@ -185,13 +195,23 @@ CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_IDENTITY = "-"; @@ -210,6 +230,7 @@ MACOSX_DEPLOYMENT_TARGET = 10.11; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = macosx; + SWIFT_COMPILATION_MODE = wholemodule; }; name = Release; }; @@ -218,10 +239,15 @@ buildSettings = { COMBINE_HIDPI_IMAGES = YES; INFOPLIST_FILE = Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + "@loader_path/../Frameworks", + ); PRODUCT_BUNDLE_IDENTIFIER = swift.algorithm.club.Tests; PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 3.0; + SWIFT_SWIFT3_OBJC_INFERENCE = Default; + SWIFT_VERSION = 4.2; }; name = Debug; }; @@ -230,10 +256,15 @@ buildSettings = { COMBINE_HIDPI_IMAGES = YES; INFOPLIST_FILE = Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + "@loader_path/../Frameworks", + ); PRODUCT_BUNDLE_IDENTIFIER = swift.algorithm.club.Tests; PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 3.0; + SWIFT_SWIFT3_OBJC_INFERENCE = Default; + SWIFT_VERSION = 4.2; }; name = Release; }; diff --git a/Binary Search Tree/Solution 1/Tests/Tests.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Binary Search Tree/Solution 1/Tests/Tests.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/Binary Search Tree/Solution 1/Tests/Tests.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/Binary Search Tree/Solution 1/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme b/Binary Search Tree/Solution 1/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme index 8ef8d8581..afd69e6a7 100644 --- a/Binary Search Tree/Solution 1/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme +++ b/Binary Search Tree/Solution 1/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme @@ -1,6 +1,6 @@ =4.0) -print("Hello, Swift 4!") -#endif - // Each time you insert something, you get back a completely new tree. var tree = BinarySearchTree.leaf(7) tree = tree.insert(newValue: 2) diff --git a/Binary Search Tree/Solution 2/BinarySearchTree.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Binary Search Tree/Solution 2/BinarySearchTree.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/Binary Search Tree/Solution 2/BinarySearchTree.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/Binary Search/BinarySearch.playground/Sources/BinarySearch.swift b/Binary Search/BinarySearch.playground/Sources/BinarySearch.swift deleted file mode 100644 index d6623e355..000000000 --- a/Binary Search/BinarySearch.playground/Sources/BinarySearch.swift +++ /dev/null @@ -1,52 +0,0 @@ -/** - Binary Search - - Recursively splits the array in half until the value is found. - - If there is more than one occurrence of the search key in the array, then - there is no guarantee which one it finds. - - Note: The array must be sorted! - **/ - -import Foundation - -// The recursive version of binary search. - -public func binarySearch(_ a: [T], key: T, range: Range) -> Int? { - if range.lowerBound >= range.upperBound { - return nil - } else { - let midIndex = range.lowerBound + (range.upperBound - range.lowerBound) / 2 - if a[midIndex] > key { - return binarySearch(a, key: key, range: range.lowerBound ..< midIndex) - } else if a[midIndex] < key { - return binarySearch(a, key: key, range: midIndex + 1 ..< range.upperBound) - } else { - return midIndex - } - } -} - -/** - The iterative version of binary search. - - Notice how similar these functions are. The difference is that this one - uses a while loop, while the other calls itself recursively. - **/ - -public func binarySearch(_ a: [T], key: T) -> Int? { - var lowerBound = 0 - var upperBound = a.count - while lowerBound < upperBound { - let midIndex = lowerBound + (upperBound - lowerBound) / 2 - if a[midIndex] == key { - return midIndex - } else if a[midIndex] < key { - lowerBound = midIndex + 1 - } else { - upperBound = midIndex - } - } - return nil -} diff --git a/Binary Search/BinarySearch.playground/playground.xcworkspace/contents.xcworkspacedata b/Binary Search/BinarySearch.playground/playground.xcworkspace/contents.xcworkspacedata deleted file mode 100644 index 919434a62..000000000 --- a/Binary Search/BinarySearch.playground/playground.xcworkspace/contents.xcworkspacedata +++ /dev/null @@ -1,7 +0,0 @@ - - - - - From 54ac83543efd7bb47d1a976fcf9016ac618c3793 Mon Sep 17 00:00:00 2001 From: KelCodesStuff Date: Thu, 4 Oct 2018 21:38:01 -0400 Subject: [PATCH 051/271] [Swift 4.2] Update Binary Search Tree --- .../Contents.swift | 5 ++ .../xcshareddata/IDEWorkspaceChecks.plist | 8 ---- .../Tests/Tests.xcodeproj/project.pbxproj | 47 ++++--------------- .../xcshareddata/IDEWorkspaceChecks.plist | 8 ---- .../xcshareddata/xcschemes/Tests.xcscheme | 2 +- .../Contents.swift | 5 ++ .../xcshareddata/IDEWorkspaceChecks.plist | 8 ---- 7 files changed, 19 insertions(+), 64 deletions(-) delete mode 100644 Binary Search Tree/Solution 1/BinarySearchTree.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist delete mode 100644 Binary Search Tree/Solution 1/Tests/Tests.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist delete mode 100644 Binary Search Tree/Solution 2/BinarySearchTree.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist diff --git a/Binary Search Tree/Solution 1/BinarySearchTree.playground/Contents.swift b/Binary Search Tree/Solution 1/BinarySearchTree.playground/Contents.swift index ec9902283..8c06ae9e1 100644 --- a/Binary Search Tree/Solution 1/BinarySearchTree.playground/Contents.swift +++ b/Binary Search Tree/Solution 1/BinarySearchTree.playground/Contents.swift @@ -1,5 +1,10 @@ //: Playground - noun: a place where people can play +// last checked with Xcode 9.0b4 +#if swift(>=4.0) +print("Hello, Swift 4!") +#endif + let tree = BinarySearchTree(value: 7) tree.insert(value: 2) tree.insert(value: 5) diff --git a/Binary Search Tree/Solution 1/BinarySearchTree.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Binary Search Tree/Solution 1/BinarySearchTree.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist deleted file mode 100644 index 18d981003..000000000 --- a/Binary Search Tree/Solution 1/BinarySearchTree.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +++ /dev/null @@ -1,8 +0,0 @@ - - - - - IDEDidComputeMac32BitWarning - - - diff --git a/Binary Search Tree/Solution 1/Tests/Tests.xcodeproj/project.pbxproj b/Binary Search Tree/Solution 1/Tests/Tests.xcodeproj/project.pbxproj index ff594fff8..f4c3f65c7 100644 --- a/Binary Search Tree/Solution 1/Tests/Tests.xcodeproj/project.pbxproj +++ b/Binary Search Tree/Solution 1/Tests/Tests.xcodeproj/project.pbxproj @@ -3,7 +3,7 @@ archiveVersion = 1; classes = { }; - objectVersion = 51; + objectVersion = 46; objects = { /* Begin PBXBuildFile section */ @@ -83,17 +83,17 @@ isa = PBXProject; attributes = { LastSwiftUpdateCheck = 0720; - LastUpgradeCheck = 1000; + LastUpgradeCheck = 0720; ORGANIZATIONNAME = "Swift Algorithm Club"; TargetAttributes = { 7B2BBC7F1C779D720067B71D = { CreatedOnToolsVersion = 7.2; - LastSwiftMigration = 1000; + LastSwiftMigration = 0820; }; }; }; buildConfigurationList = 7B2BBC6C1C779D710067B71D /* Build configuration list for PBXProject "Tests" */; - compatibilityVersion = "Xcode 10.0"; + compatibilityVersion = "Xcode 3.2"; developmentRegion = English; hasScannedForEncodings = 0; knownRegions = ( @@ -141,23 +141,13 @@ CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_IDENTITY = "-"; @@ -195,23 +185,13 @@ CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_IDENTITY = "-"; @@ -230,7 +210,6 @@ MACOSX_DEPLOYMENT_TARGET = 10.11; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = macosx; - SWIFT_COMPILATION_MODE = wholemodule; }; name = Release; }; @@ -239,15 +218,10 @@ buildSettings = { COMBINE_HIDPI_IMAGES = YES; INFOPLIST_FILE = Info.plist; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/../Frameworks", - "@loader_path/../Frameworks", - ); + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = swift.algorithm.club.Tests; PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_SWIFT3_OBJC_INFERENCE = Default; - SWIFT_VERSION = 4.2; + SWIFT_VERSION = 3.0; }; name = Debug; }; @@ -256,15 +230,10 @@ buildSettings = { COMBINE_HIDPI_IMAGES = YES; INFOPLIST_FILE = Info.plist; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/../Frameworks", - "@loader_path/../Frameworks", - ); + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = swift.algorithm.club.Tests; PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_SWIFT3_OBJC_INFERENCE = Default; - SWIFT_VERSION = 4.2; + SWIFT_VERSION = 3.0; }; name = Release; }; diff --git a/Binary Search Tree/Solution 1/Tests/Tests.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Binary Search Tree/Solution 1/Tests/Tests.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist deleted file mode 100644 index 18d981003..000000000 --- a/Binary Search Tree/Solution 1/Tests/Tests.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +++ /dev/null @@ -1,8 +0,0 @@ - - - - - IDEDidComputeMac32BitWarning - - - diff --git a/Binary Search Tree/Solution 1/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme b/Binary Search Tree/Solution 1/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme index afd69e6a7..8ef8d8581 100644 --- a/Binary Search Tree/Solution 1/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme +++ b/Binary Search Tree/Solution 1/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme @@ -1,6 +1,6 @@ =4.0) +print("Hello, Swift 4!") +#endif + // Each time you insert something, you get back a completely new tree. var tree = BinarySearchTree.leaf(7) tree = tree.insert(newValue: 2) diff --git a/Binary Search Tree/Solution 2/BinarySearchTree.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Binary Search Tree/Solution 2/BinarySearchTree.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist deleted file mode 100644 index 18d981003..000000000 --- a/Binary Search Tree/Solution 2/BinarySearchTree.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +++ /dev/null @@ -1,8 +0,0 @@ - - - - - IDEDidComputeMac32BitWarning - - - From d6099b34226cef00bc5e83fa503437c88fbd39b2 Mon Sep 17 00:00:00 2001 From: KelCodesStuff Date: Thu, 4 Oct 2018 21:38:36 -0400 Subject: [PATCH 052/271] [Swift 4.2] Dijkstra Algorithm --- Dijkstra Algorithm/Dijkstra.playground/Contents.swift | 5 ----- .../xcshareddata/IDEWorkspaceChecks.plist | 8 ++++++++ .../VisualizedDijkstra.playground/Contents.swift | 5 ----- .../VisualizedDijkstra.playground/Sources/Window.swift | 2 +- .../xcshareddata/IDEWorkspaceChecks.plist | 8 ++++++++ 5 files changed, 17 insertions(+), 11 deletions(-) create mode 100644 Dijkstra Algorithm/Dijkstra.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist create mode 100644 Dijkstra Algorithm/VisualizedDijkstra.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist diff --git a/Dijkstra Algorithm/Dijkstra.playground/Contents.swift b/Dijkstra Algorithm/Dijkstra.playground/Contents.swift index 1cd1254b1..7c7f1a4b0 100644 --- a/Dijkstra Algorithm/Dijkstra.playground/Contents.swift +++ b/Dijkstra Algorithm/Dijkstra.playground/Contents.swift @@ -1,11 +1,6 @@ //: Playground - noun: a place where people can play import Foundation -// last checked with Xcode 9.0b4 -#if swift(>=4.0) -print("Hello, Swift 4!") -#endif - var vertices: Set = Set() func createNotConnectedVertices() { diff --git a/Dijkstra Algorithm/Dijkstra.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Dijkstra Algorithm/Dijkstra.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/Dijkstra Algorithm/Dijkstra.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/Dijkstra Algorithm/VisualizedDijkstra.playground/Contents.swift b/Dijkstra Algorithm/VisualizedDijkstra.playground/Contents.swift index 8e61ef49b..de6b49834 100644 --- a/Dijkstra Algorithm/VisualizedDijkstra.playground/Contents.swift +++ b/Dijkstra Algorithm/VisualizedDijkstra.playground/Contents.swift @@ -9,11 +9,6 @@ import UIKit import PlaygroundSupport -// last checked with Xcode 9.0b4 -#if swift(>=4.0) -print("Hello, Swift 4!") -#endif - /*: First of all, let's set up colors for our window and graph. The visited color will be applied to visited vertices. The checking color will be applied to an edge and an edge neighbor every time the algorithm is checking some vertex neighbors. And default colors are just initial colors for elements. */ diff --git a/Dijkstra Algorithm/VisualizedDijkstra.playground/Sources/Window.swift b/Dijkstra Algorithm/VisualizedDijkstra.playground/Sources/Window.swift index 73c512e6b..9a169b8c7 100644 --- a/Dijkstra Algorithm/VisualizedDijkstra.playground/Sources/Window.swift +++ b/Dijkstra Algorithm/VisualizedDijkstra.playground/Sources/Window.swift @@ -134,7 +134,7 @@ public class Window: UIView, GraphDelegate { let origin = CGPoint(x: center.x - 25, y: 100) let activityIndicatorFrame = CGRect(origin: origin, size: size) activityIndicator = UIActivityIndicatorView(frame: activityIndicatorFrame) - activityIndicator.activityIndicatorViewStyle = .whiteLarge + activityIndicator.style = .whiteLarge } @objc private func createGraphButtonTap() { diff --git a/Dijkstra Algorithm/VisualizedDijkstra.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Dijkstra Algorithm/VisualizedDijkstra.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/Dijkstra Algorithm/VisualizedDijkstra.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + From e6a2aa77f23a515081d8bc806e46efc81d785321 Mon Sep 17 00:00:00 2001 From: KelCodesStuff Date: Thu, 4 Oct 2018 21:43:56 -0400 Subject: [PATCH 053/271] [Swift 4.2] Update Binary Search Tree --- .../Contents.swift | 5 --- .../xcshareddata/IDEWorkspaceChecks.plist | 8 +++++ .../Tests/Tests.xcodeproj/project.pbxproj | 31 ++++++++++++++++--- .../xcshareddata/IDEWorkspaceChecks.plist | 8 +++++ .../xcshareddata/xcschemes/Tests.xcscheme | 2 +- .../Contents.swift | 5 --- .../xcshareddata/IDEWorkspaceChecks.plist | 8 +++++ 7 files changed, 52 insertions(+), 15 deletions(-) create mode 100644 Binary Search Tree/Solution 1/BinarySearchTree.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist create mode 100644 Binary Search Tree/Solution 1/Tests/Tests.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist create mode 100644 Binary Search Tree/Solution 2/BinarySearchTree.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist diff --git a/Binary Search Tree/Solution 1/BinarySearchTree.playground/Contents.swift b/Binary Search Tree/Solution 1/BinarySearchTree.playground/Contents.swift index 8c06ae9e1..ec9902283 100644 --- a/Binary Search Tree/Solution 1/BinarySearchTree.playground/Contents.swift +++ b/Binary Search Tree/Solution 1/BinarySearchTree.playground/Contents.swift @@ -1,10 +1,5 @@ //: Playground - noun: a place where people can play -// last checked with Xcode 9.0b4 -#if swift(>=4.0) -print("Hello, Swift 4!") -#endif - let tree = BinarySearchTree(value: 7) tree.insert(value: 2) tree.insert(value: 5) diff --git a/Binary Search Tree/Solution 1/BinarySearchTree.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Binary Search Tree/Solution 1/BinarySearchTree.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/Binary Search Tree/Solution 1/BinarySearchTree.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/Binary Search Tree/Solution 1/Tests/Tests.xcodeproj/project.pbxproj b/Binary Search Tree/Solution 1/Tests/Tests.xcodeproj/project.pbxproj index f4c3f65c7..d7c687e0c 100644 --- a/Binary Search Tree/Solution 1/Tests/Tests.xcodeproj/project.pbxproj +++ b/Binary Search Tree/Solution 1/Tests/Tests.xcodeproj/project.pbxproj @@ -83,12 +83,12 @@ isa = PBXProject; attributes = { LastSwiftUpdateCheck = 0720; - LastUpgradeCheck = 0720; + LastUpgradeCheck = 1000; ORGANIZATIONNAME = "Swift Algorithm Club"; TargetAttributes = { 7B2BBC7F1C779D720067B71D = { CreatedOnToolsVersion = 7.2; - LastSwiftMigration = 0820; + LastSwiftMigration = 1000; }; }; }; @@ -141,13 +141,23 @@ CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_IDENTITY = "-"; @@ -185,13 +195,23 @@ CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_IDENTITY = "-"; @@ -210,6 +230,7 @@ MACOSX_DEPLOYMENT_TARGET = 10.11; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = macosx; + SWIFT_COMPILATION_MODE = wholemodule; }; name = Release; }; @@ -221,7 +242,8 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = swift.algorithm.club.Tests; PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 3.0; + SWIFT_SWIFT3_OBJC_INFERENCE = Default; + SWIFT_VERSION = 4.2; }; name = Debug; }; @@ -233,7 +255,8 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = swift.algorithm.club.Tests; PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 3.0; + SWIFT_SWIFT3_OBJC_INFERENCE = Default; + SWIFT_VERSION = 4.2; }; name = Release; }; diff --git a/Binary Search Tree/Solution 1/Tests/Tests.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Binary Search Tree/Solution 1/Tests/Tests.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/Binary Search Tree/Solution 1/Tests/Tests.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/Binary Search Tree/Solution 1/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme b/Binary Search Tree/Solution 1/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme index 8ef8d8581..afd69e6a7 100644 --- a/Binary Search Tree/Solution 1/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme +++ b/Binary Search Tree/Solution 1/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme @@ -1,6 +1,6 @@ =4.0) -print("Hello, Swift 4!") -#endif - // Each time you insert something, you get back a completely new tree. var tree = BinarySearchTree.leaf(7) tree = tree.insert(newValue: 2) diff --git a/Binary Search Tree/Solution 2/BinarySearchTree.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Binary Search Tree/Solution 2/BinarySearchTree.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/Binary Search Tree/Solution 2/BinarySearchTree.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + From 1d452b31d82f06ad964ae5acd6d0bd7e8b2cadd8 Mon Sep 17 00:00:00 2001 From: KelCodesStuff Date: Thu, 4 Oct 2018 22:01:22 -0400 Subject: [PATCH 054/271] [Swift 4.2] Queue --- Queue/Tests/Tests.xcodeproj/project.pbxproj | 26 ++++++++++++++++--- .../xcshareddata/IDEWorkspaceChecks.plist | 8 ++++++ .../xcshareddata/xcschemes/Tests.xcscheme | 2 +- 3 files changed, 31 insertions(+), 5 deletions(-) create mode 100644 Queue/Tests/Tests.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist diff --git a/Queue/Tests/Tests.xcodeproj/project.pbxproj b/Queue/Tests/Tests.xcodeproj/project.pbxproj index a554fd16e..f7fc3e048 100644 --- a/Queue/Tests/Tests.xcodeproj/project.pbxproj +++ b/Queue/Tests/Tests.xcodeproj/project.pbxproj @@ -83,12 +83,12 @@ isa = PBXProject; attributes = { LastSwiftUpdateCheck = 0720; - LastUpgradeCheck = 0800; + LastUpgradeCheck = 1000; ORGANIZATIONNAME = "Swift Algorithm Club"; TargetAttributes = { 7B2BBC7F1C779D720067B71D = { CreatedOnToolsVersion = 7.2; - LastSwiftMigration = 0800; + LastSwiftMigration = 1000; }; }; }; @@ -141,14 +141,22 @@ CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; @@ -187,14 +195,22 @@ CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; @@ -226,7 +242,8 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = swift.algorithm.club.Tests; PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 3.0; + SWIFT_SWIFT3_OBJC_INFERENCE = On; + SWIFT_VERSION = 4.2; }; name = Debug; }; @@ -238,7 +255,8 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = swift.algorithm.club.Tests; PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 3.0; + SWIFT_SWIFT3_OBJC_INFERENCE = On; + SWIFT_VERSION = 4.2; }; name = Release; }; diff --git a/Queue/Tests/Tests.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Queue/Tests/Tests.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/Queue/Tests/Tests.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/Queue/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme b/Queue/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme index 14f27f777..afd69e6a7 100644 --- a/Queue/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme +++ b/Queue/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme @@ -1,6 +1,6 @@ Date: Thu, 4 Oct 2018 22:05:37 -0400 Subject: [PATCH 055/271] [Swift 4.2] Queue --- Queue/Queue.playground/Contents.swift | 6 ------ .../xcshareddata/IDEWorkspaceChecks.plist | 8 ++++++++ Queue/Tests/Tests.xcodeproj/project.pbxproj | 4 ++-- 3 files changed, 10 insertions(+), 8 deletions(-) create mode 100644 Queue/Queue.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist diff --git a/Queue/Queue.playground/Contents.swift b/Queue/Queue.playground/Contents.swift index 22d2a84ca..08327783f 100644 --- a/Queue/Queue.playground/Contents.swift +++ b/Queue/Queue.playground/Contents.swift @@ -1,9 +1,3 @@ - -// last checked with Xcode 9.0b4 -#if swift(>=4.0) -print("Hello, Swift 4!") -#endif - /* Queue diff --git a/Queue/Queue.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Queue/Queue.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/Queue/Queue.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/Queue/Tests/Tests.xcodeproj/project.pbxproj b/Queue/Tests/Tests.xcodeproj/project.pbxproj index f7fc3e048..f927aba0d 100644 --- a/Queue/Tests/Tests.xcodeproj/project.pbxproj +++ b/Queue/Tests/Tests.xcodeproj/project.pbxproj @@ -242,7 +242,7 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = swift.algorithm.club.Tests; PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_SWIFT3_OBJC_INFERENCE = On; + SWIFT_SWIFT3_OBJC_INFERENCE = Default; SWIFT_VERSION = 4.2; }; name = Debug; @@ -255,7 +255,7 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = swift.algorithm.club.Tests; PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_SWIFT3_OBJC_INFERENCE = On; + SWIFT_SWIFT3_OBJC_INFERENCE = Default; SWIFT_VERSION = 4.2; }; name = Release; From 01ba34cc5084c7f70beb3955d71918f75fb30bd0 Mon Sep 17 00:00:00 2001 From: KelCodesStuff Date: Thu, 4 Oct 2018 22:17:58 -0400 Subject: [PATCH 056/271] [Swift 4.2] Merge Sort --- Merge Sort/MergeSort.playground/Contents.swift | 5 ----- .../xcshareddata/IDEWorkspaceChecks.plist | 8 ++++++++ 2 files changed, 8 insertions(+), 5 deletions(-) create mode 100644 Merge Sort/MergeSort.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist diff --git a/Merge Sort/MergeSort.playground/Contents.swift b/Merge Sort/MergeSort.playground/Contents.swift index b05332bfe..ca1347890 100644 --- a/Merge Sort/MergeSort.playground/Contents.swift +++ b/Merge Sort/MergeSort.playground/Contents.swift @@ -1,10 +1,5 @@ /* Top-down recursive version */ -// last checked with Xcode 9.0b4 -#if swift(>=4.0) -print("Hello, Swift 4!") -#endif - func mergeSort(_ array: [T]) -> [T] { guard array.count > 1 else { return array } let middleIndex = array.count / 2 diff --git a/Merge Sort/MergeSort.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Merge Sort/MergeSort.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/Merge Sort/MergeSort.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + From 3f0bdc6ec0009bf08251458a04b11631d13cb7c7 Mon Sep 17 00:00:00 2001 From: danielchick Date: Thu, 4 Oct 2018 22:44:53 -0500 Subject: [PATCH 057/271] [Swift 4.2] Update Tree --- Tree/Tree.playground/Contents.swift | 4 ++-- Tree/Tree.playground/contents.xcplayground | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Tree/Tree.playground/Contents.swift b/Tree/Tree.playground/Contents.swift index 49cf41054..06f992fa8 100644 --- a/Tree/Tree.playground/Contents.swift +++ b/Tree/Tree.playground/Contents.swift @@ -1,8 +1,8 @@ //: Playground - noun: a place where people can play // last checked with Xcode 9.0b4 -#if swift(>=4.0) -print("Hello, Swift 4!") +#if swift(>=4.2) +print("Hello, Swift 4.2!") #endif let tree = TreeNode(value: "beverages") diff --git a/Tree/Tree.playground/contents.xcplayground b/Tree/Tree.playground/contents.xcplayground index 06828af92..69d154d1e 100644 --- a/Tree/Tree.playground/contents.xcplayground +++ b/Tree/Tree.playground/contents.xcplayground @@ -1,4 +1,4 @@ - + \ No newline at end of file From f24a004b0420dcd3dc3156b368852e30b9841e89 Mon Sep 17 00:00:00 2001 From: imvm Date: Fri, 5 Oct 2018 02:51:06 -0300 Subject: [PATCH 058/271] Remove notice from Strassen Multiplication Matrix playground --- .../StrassensMatrixMultiplication.playground/Contents.swift | 5 ----- 1 file changed, 5 deletions(-) diff --git a/Strassen Matrix Multiplication/StrassensMatrixMultiplication.playground/Contents.swift b/Strassen Matrix Multiplication/StrassensMatrixMultiplication.playground/Contents.swift index 409e28c52..6b9314557 100644 --- a/Strassen Matrix Multiplication/StrassensMatrixMultiplication.playground/Contents.swift +++ b/Strassen Matrix Multiplication/StrassensMatrixMultiplication.playground/Contents.swift @@ -1,10 +1,5 @@ //: Playground - noun: a place where people can play -// last checked with Xcode 9.0b4 -#if swift(>=4.0) -print("Hello, Swift 4!") -#endif - import Foundation var A = Matrix(rows: 2, columns: 4, initialValue: 0) From 6ab163e4431ba09a6870b4b101dc536cffcf759d Mon Sep 17 00:00:00 2001 From: Bruno Scheele Date: Fri, 5 Oct 2018 09:34:07 +0200 Subject: [PATCH 059/271] Update to Xcode 10. --- Bucket Sort/Tests/Tests.xcodeproj/project.pbxproj | 6 +++++- .../xcshareddata/IDEWorkspaceChecks.plist | 8 ++++++++ .../Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme | 4 +--- 3 files changed, 14 insertions(+), 4 deletions(-) create mode 100644 Bucket Sort/Tests/Tests.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist diff --git a/Bucket Sort/Tests/Tests.xcodeproj/project.pbxproj b/Bucket Sort/Tests/Tests.xcodeproj/project.pbxproj index 84a305784..6df507720 100644 --- a/Bucket Sort/Tests/Tests.xcodeproj/project.pbxproj +++ b/Bucket Sort/Tests/Tests.xcodeproj/project.pbxproj @@ -83,7 +83,7 @@ isa = PBXProject; attributes = { LastSwiftUpdateCheck = 0730; - LastUpgradeCheck = 0900; + LastUpgradeCheck = 1000; ORGANIZATIONNAME = "Swift Algorithm Club"; TargetAttributes = { 7B2BBC7F1C779D720067B71D = { @@ -145,12 +145,14 @@ CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; @@ -197,12 +199,14 @@ CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; diff --git a/Bucket Sort/Tests/Tests.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Bucket Sort/Tests/Tests.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/Bucket Sort/Tests/Tests.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/Bucket Sort/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme b/Bucket Sort/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme index 538a6f4fa..afd69e6a7 100644 --- a/Bucket Sort/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme +++ b/Bucket Sort/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme @@ -1,6 +1,6 @@ Date: Fri, 5 Oct 2018 09:49:56 +0200 Subject: [PATCH 060/271] Refactor to remove dependency on pre-Swift 4. The code used to depend on pre-Swift 4's optional operators, which have since been replaced. Now, the one possible case for comparing a potential `nil` maximum value has been handled. --- Bucket Sort/BucketSort.swift | 31 +++++-------------------------- 1 file changed, 5 insertions(+), 26 deletions(-) diff --git a/Bucket Sort/BucketSort.swift b/Bucket Sort/BucketSort.swift index 108073288..4c2abd372 100644 --- a/Bucket Sort/BucketSort.swift +++ b/Bucket Sort/BucketSort.swift @@ -20,31 +20,6 @@ // // -import Foundation -// FIXME: comparison operators with optionals were removed from the Swift Standard Libary. -// Consider refactoring the code to use the non-optional operators. -fileprivate func < (lhs: T?, rhs: T?) -> Bool { - switch (lhs, rhs) { - case let (l?, r?): - return l < r - case (nil, _?): - return true - default: - return false - } -} - -// FIXME: comparison operators with optionals were removed from the Swift Standard Libary. -// Consider refactoring the code to use the non-optional operators. -fileprivate func >= (lhs: T?, rhs: T?) -> Bool { - switch (lhs, rhs) { - case let (l?, r?): - return l >= r - default: - return !(lhs < rhs) - } -} - ////////////////////////////////////// // MARK: Main algorithm ////////////////////////////////////// @@ -87,7 +62,11 @@ private func enoughSpaceInBuckets(_ buckets: [Bucket], elements: [T]) -> B let maximumValue = elements.max()?.toInt() let totalCapacity = buckets.count * (buckets.first?.capacity)! - return totalCapacity >= maximumValue + guard let max = maximumValue else { + return false + } + + return totalCapacity >= max } ////////////////////////////////////// From 8f2bf19304b379d60551359f913080e22b8d7ed3 Mon Sep 17 00:00:00 2001 From: Bruno Scheele Date: Fri, 5 Oct 2018 09:55:40 +0200 Subject: [PATCH 061/271] Change playground as well. --- .../Sources/BucketSort.swift | 31 +++---------------- .../contents.xcplayground | 2 +- .../xcshareddata/IDEWorkspaceChecks.plist | 8 +++++ 3 files changed, 14 insertions(+), 27 deletions(-) create mode 100644 Bucket Sort/BucketSort.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist diff --git a/Bucket Sort/BucketSort.playground/Sources/BucketSort.swift b/Bucket Sort/BucketSort.playground/Sources/BucketSort.swift index bafd216fa..64408eca4 100644 --- a/Bucket Sort/BucketSort.playground/Sources/BucketSort.swift +++ b/Bucket Sort/BucketSort.playground/Sources/BucketSort.swift @@ -20,31 +20,6 @@ // // -import Foundation -// FIXME: comparison operators with optionals were removed from the Swift Standard Libary. -// Consider refactoring the code to use the non-optional operators. -fileprivate func < (lhs: T?, rhs: T?) -> Bool { - switch (lhs, rhs) { - case let (l?, r?): - return l < r - case (nil, _?): - return true - default: - return false - } -} - -// FIXME: comparison operators with optionals were removed from the Swift Standard Libary. -// Consider refactoring the code to use the non-optional operators. -fileprivate func >= (lhs: T?, rhs: T?) -> Bool { - switch (lhs, rhs) { - case let (l?, r?): - return l >= r - default: - return !(lhs < rhs) - } -} - ////////////////////////////////////// // MARK: Main algorithm ////////////////////////////////////// @@ -87,7 +62,11 @@ private func enoughSpaceInBuckets(_ buckets: [Bucket], elements: [T]) -> B let maximumValue = elements.max()?.toInt() let totalCapacity = buckets.count * (buckets.first?.capacity)! - return totalCapacity >= maximumValue + guard let max = maximumValue else { + return false + } + + return totalCapacity >= max } ////////////////////////////////////// diff --git a/Bucket Sort/BucketSort.playground/contents.xcplayground b/Bucket Sort/BucketSort.playground/contents.xcplayground index 5da2641c9..9f5f2f40c 100644 --- a/Bucket Sort/BucketSort.playground/contents.xcplayground +++ b/Bucket Sort/BucketSort.playground/contents.xcplayground @@ -1,4 +1,4 @@ - + \ No newline at end of file diff --git a/Bucket Sort/BucketSort.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Bucket Sort/BucketSort.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/Bucket Sort/BucketSort.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + From f28973201916ac83c3b95f4115215a09715d22b7 Mon Sep 17 00:00:00 2001 From: Bruno Scheele Date: Fri, 5 Oct 2018 09:58:24 +0200 Subject: [PATCH 062/271] Add credit to README. --- Bucket Sort/README.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Bucket Sort/README.markdown b/Bucket Sort/README.markdown index f572fc9a1..f2708d71e 100644 --- a/Bucket Sort/README.markdown +++ b/Bucket Sort/README.markdown @@ -256,4 +256,4 @@ The following are some of the variation to the general [Bucket Sort](https://en. - [Postman Sort](https://en.wikipedia.org/wiki/Bucket_sort#Postman.27s_sort) - [Shuffle Sort](https://en.wikipedia.org/wiki/Bucket_sort#Shuffle_sort) -*Written for Swift Algorithm Club by Barbara Rodeker. Images from Wikipedia.* +*Written for Swift Algorithm Club by Barbara Rodeker. Images from Wikipedia. Updated by Bruno Scheele.* From 184786db68a17e40cfe2e4de6f7f212a84db42d4 Mon Sep 17 00:00:00 2001 From: KelCodesStuff Date: Fri, 5 Oct 2018 21:27:02 -0400 Subject: [PATCH 063/271] [Swift 4.2] Threaded Binary Tree --- .../ThreadedBinaryTree.playground/Contents.swift | 5 ----- .../xcshareddata/IDEWorkspaceChecks.plist | 8 ++++++++ 2 files changed, 8 insertions(+), 5 deletions(-) create mode 100644 Threaded Binary Tree/ThreadedBinaryTree.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist diff --git a/Threaded Binary Tree/ThreadedBinaryTree.playground/Contents.swift b/Threaded Binary Tree/ThreadedBinaryTree.playground/Contents.swift index 4ce9d8157..ece1966e0 100644 --- a/Threaded Binary Tree/ThreadedBinaryTree.playground/Contents.swift +++ b/Threaded Binary Tree/ThreadedBinaryTree.playground/Contents.swift @@ -1,10 +1,5 @@ //: Playground - noun: a place where people can play -// last checked with Xcode 9.0b4 -#if swift(>=4.0) -print("Hello, Swift 4!") -#endif - // Simple little debug function to make testing output pretty func check(_ tree: ThreadedBinaryTree?) { if let tree = tree { diff --git a/Threaded Binary Tree/ThreadedBinaryTree.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Threaded Binary Tree/ThreadedBinaryTree.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/Threaded Binary Tree/ThreadedBinaryTree.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + From cafba43a1c38bad9f62400e42ef46b9f51c60df3 Mon Sep 17 00:00:00 2001 From: Aleph Retamal Date: Sat, 6 Oct 2018 18:11:50 +1000 Subject: [PATCH 064/271] [Swift 4.2] Update K-Means --- K-Means/KMeans.swift | 2 +- K-Means/Tests/KMeansTests.swift | 7 ------ K-Means/Tests/Tests.xcodeproj/project.pbxproj | 24 +++++++++++++++---- .../xcshareddata/IDEWorkspaceChecks.plist | 8 +++++++ .../xcshareddata/xcschemes/Tests.xcscheme | 2 +- 5 files changed, 30 insertions(+), 13 deletions(-) create mode 100644 K-Means/Tests/Tests.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist diff --git a/K-Means/KMeans.swift b/K-Means/KMeans.swift index 4a89a3fae..bccc6efd3 100644 --- a/K-Means/KMeans.swift +++ b/K-Means/KMeans.swift @@ -12,7 +12,7 @@ class KMeans { } private func indexOfNearestCenter(_ x: Vector, centers: [Vector]) -> Int { - var nearestDist = DBL_MAX + var nearestDist = Double.greatestFiniteMagnitude var minIndex = 0 for (idx, center) in centers.enumerated() { diff --git a/K-Means/Tests/KMeansTests.swift b/K-Means/Tests/KMeansTests.swift index e6f4b08a1..7e0c93004 100644 --- a/K-Means/Tests/KMeansTests.swift +++ b/K-Means/Tests/KMeansTests.swift @@ -10,13 +10,6 @@ import Foundation import XCTest class KMeansTests: XCTestCase { - func testSwift4() { - // last checked with Xcode 9.0b4 - #if swift(>=4.0) - print("Hello, Swift 4!") - #endif - } - func genPoints(_ numPoints: Int, numDimensions: Int) -> [Vector] { var points = [Vector]() for _ in 0.. + + + + IDEDidComputeMac32BitWarning + + + diff --git a/K-Means/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme b/K-Means/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme index 2b401e86e..73ba8f37d 100644 --- a/K-Means/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme +++ b/K-Means/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme @@ -1,6 +1,6 @@ Date: Sat, 6 Oct 2018 19:28:22 +1000 Subject: [PATCH 065/271] [Swift 4.2] Update Egg Drop Problem --- Egg Drop Problem/EggDrop.playground/Contents.swift | 4 ---- .../xcshareddata/IDEWorkspaceChecks.plist | 8 ++++++++ .../xcshareddata/WorkspaceSettings.xcsettings | 5 +++++ 3 files changed, 13 insertions(+), 4 deletions(-) create mode 100644 Egg Drop Problem/EggDrop.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist create mode 100644 Egg Drop Problem/EggDrop.playground/playground.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings diff --git a/Egg Drop Problem/EggDrop.playground/Contents.swift b/Egg Drop Problem/EggDrop.playground/Contents.swift index 0b707da98..decaacdca 100644 --- a/Egg Drop Problem/EggDrop.playground/Contents.swift +++ b/Egg Drop Problem/EggDrop.playground/Contents.swift @@ -1,7 +1,3 @@ -#if swift(>=4.0) - print("Hello, Swift 4!") -#endif - drop(numberOfEggs: 2, numberOfFloors: 2) //expected answer: 2 drop(numberOfEggs: 2, numberOfFloors: 4) //expected answer: 3 drop(numberOfEggs: 2, numberOfFloors: 6) //expected answer: 3 diff --git a/Egg Drop Problem/EggDrop.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Egg Drop Problem/EggDrop.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/Egg Drop Problem/EggDrop.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/Egg Drop Problem/EggDrop.playground/playground.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/Egg Drop Problem/EggDrop.playground/playground.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 000000000..0c67376eb --- /dev/null +++ b/Egg Drop Problem/EggDrop.playground/playground.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,5 @@ + + + + + From 2d60bb78c249085c47714474d27d97297a09fa2f Mon Sep 17 00:00:00 2001 From: askari01 Date: Sat, 6 Oct 2018 23:02:19 +0500 Subject: [PATCH 066/271] 2 sum problem with swift 4.2 --- Two-Sum Problem/Solution 1/2Sum.playground/Contents.swift | 5 +---- .../xcshareddata/IDEWorkspaceChecks.plist | 8 ++++++++ Two-Sum Problem/Solution 2/2Sum.playground/Contents.swift | 5 +---- .../xcshareddata/IDEWorkspaceChecks.plist | 8 ++++++++ 4 files changed, 18 insertions(+), 8 deletions(-) create mode 100644 Two-Sum Problem/Solution 1/2Sum.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist create mode 100644 Two-Sum Problem/Solution 2/2Sum.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist diff --git a/Two-Sum Problem/Solution 1/2Sum.playground/Contents.swift b/Two-Sum Problem/Solution 1/2Sum.playground/Contents.swift index 26bfae449..00a39b04a 100644 --- a/Two-Sum Problem/Solution 1/2Sum.playground/Contents.swift +++ b/Two-Sum Problem/Solution 1/2Sum.playground/Contents.swift @@ -1,8 +1,5 @@ //: Two Sum -// Last checked with: Version 9.0 (9A235) -#if swift(>=4.0) -print("Hello, Swift 4!") -#endif +// Last checked with: Version 10.0 (10A255) func twoSum(_ nums: [Int], target: Int) -> (Int, Int)? { var dict = [Int: Int]() diff --git a/Two-Sum Problem/Solution 1/2Sum.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Two-Sum Problem/Solution 1/2Sum.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/Two-Sum Problem/Solution 1/2Sum.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/Two-Sum Problem/Solution 2/2Sum.playground/Contents.swift b/Two-Sum Problem/Solution 2/2Sum.playground/Contents.swift index 4cb3d9283..469c15b5f 100644 --- a/Two-Sum Problem/Solution 2/2Sum.playground/Contents.swift +++ b/Two-Sum Problem/Solution 2/2Sum.playground/Contents.swift @@ -1,8 +1,5 @@ //: Playground - noun: a place where people can play -// Last checked with: Version 9.0 beta 4 (9M189t) -#if swift(>=4.0) -print("Hello, Swift 4!") -#endif +// Last checked with: Version 10.0 (10A255) func twoSumProblem(_ a: [Int], k: Int) -> ((Int, Int))? { var i = 0 diff --git a/Two-Sum Problem/Solution 2/2Sum.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Two-Sum Problem/Solution 2/2Sum.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/Two-Sum Problem/Solution 2/2Sum.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + From f0ce485316036d977470c7d38e9a1959e8a60f08 Mon Sep 17 00:00:00 2001 From: askari01 Date: Sat, 6 Oct 2018 23:08:23 +0500 Subject: [PATCH 067/271] updated readme for 2 sum problem with swift 4.2 --- Two-Sum Problem/README.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Two-Sum Problem/README.markdown b/Two-Sum Problem/README.markdown index 4d8ffcd95..bbd033343 100644 --- a/Two-Sum Problem/README.markdown +++ b/Two-Sum Problem/README.markdown @@ -168,4 +168,4 @@ I'm quite enamored by this little algorithm. It shows that with some basic prepr * [3Sum / 4Sum](https://github.com/raywenderlich/swift-algorithm-club/tree/master/3Sum%20and%204Sum) -*Written for Swift Algorithm Club by Matthijs Hollemans and Daniel Speiser* +*Written for Swift Algorithm Club by Matthijs Hollemans and Daniel Speiser updated to swift 4.2 by Farrukh Askari* From 86d6cd114d34a602f987ab0f7a7b21d1ff7580ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Afonso=20Gra=C3=A7a?= Date: Mon, 8 Oct 2018 19:06:01 +1100 Subject: [PATCH 068/271] [Swift 4.2] Update Karatsuba multiplication Changed the way the characters in a String were accessed since `characters` was deprecated on Swift 4.0. Removed the code snippet at the beggining of the file. --- .../Contents.swift | 17 +++++++---------- .../xcshareddata/IDEWorkspaceChecks.plist | 8 ++++++++ .../KaratsubaMultiplication.swift | 12 ++++++------ 3 files changed, 21 insertions(+), 16 deletions(-) create mode 100644 Karatsuba Multiplication/KaratsubaMultiplication.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist diff --git a/Karatsuba Multiplication/KaratsubaMultiplication.playground/Contents.swift b/Karatsuba Multiplication/KaratsubaMultiplication.playground/Contents.swift index 04aff1ec4..e0ce23b19 100644 --- a/Karatsuba Multiplication/KaratsubaMultiplication.playground/Contents.swift +++ b/Karatsuba Multiplication/KaratsubaMultiplication.playground/Contents.swift @@ -1,10 +1,7 @@ //: Playground - noun: a place where people can play import Foundation -// last checked with Xcode 9.0b4 -#if swift(>=4.0) -print("Hello, Swift 4") -#endif + precedencegroup ExponentiativePrecedence { higherThan: MultiplicationPrecedence lowerThan: BitwiseShiftPrecedence @@ -18,8 +15,8 @@ func ^^ (radix: Int, power: Int) -> Int { // Long Multiplication - O(n^2) func multiply(_ num1: Int, by num2: Int, base: Int = 10) -> Int { - let num1Array = String(num1).characters.reversed().map { Int(String($0))! } - let num2Array = String(num2).characters.reversed().map { Int(String($0))! } + let num1Array = String(num1).reversed().map { Int(String($0))! } + let num2Array = String(num2).reversed().map { Int(String($0))! } var product = Array(repeating: 0, count: num1Array.count + num2Array.count) @@ -38,14 +35,14 @@ func multiply(_ num1: Int, by num2: Int, base: Int = 10) -> Int { // Karatsuba Multiplication - O(n^log2(3)) func karatsuba(_ num1: Int, by num2: Int) -> Int { - let num1Array = String(num1).characters - let num2Array = String(num2).characters + let num1String = String(num1) + let num2String = String(num2) - guard num1Array.count > 1 && num2Array.count > 1 else { + guard num1String.count > 1 && num2String.count > 1 else { return multiply(num1, by: num2) } - let n = max(num1Array.count, num2Array.count) + let n = max(num1String.count, num2String.count) let nBy2 = n / 2 let a = num1 / 10^^nBy2 diff --git a/Karatsuba Multiplication/KaratsubaMultiplication.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Karatsuba Multiplication/KaratsubaMultiplication.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/Karatsuba Multiplication/KaratsubaMultiplication.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/Karatsuba Multiplication/KaratsubaMultiplication.swift b/Karatsuba Multiplication/KaratsubaMultiplication.swift index fb20a667d..a82e82658 100644 --- a/Karatsuba Multiplication/KaratsubaMultiplication.swift +++ b/Karatsuba Multiplication/KaratsubaMultiplication.swift @@ -20,14 +20,14 @@ func ^^ (radix: Int, power: Int) -> Int { } func karatsuba(_ num1: Int, by num2: Int) -> Int { - let num1Array = String(num1).characters - let num2Array = String(num2).characters + let num1String = String(num1) + let num2String = String(num2) - guard num1Array.count > 1 && num2Array.count > 1 else { - return num1 * num2 + guard num1String.count > 1 && num2String.count > 1 else { + return multiply(num1, by: num2) } - - let n = max(num1Array.count, num2Array.count) + + let n = max(num1String.count, num2String.count) let nBy2 = n / 2 let a = num1 / 10^^nBy2 From ab20d205384c4fc40908f99dcfb941d485cac3c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Afonso=20Gra=C3=A7a?= Date: Mon, 8 Oct 2018 19:22:09 +1100 Subject: [PATCH 069/271] [Swift 4.2] Update README.md for Karatsuba multiplication --- Karatsuba Multiplication/README.markdown | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Karatsuba Multiplication/README.markdown b/Karatsuba Multiplication/README.markdown index c86f69831..3a48ed39d 100644 --- a/Karatsuba Multiplication/README.markdown +++ b/Karatsuba Multiplication/README.markdown @@ -71,15 +71,15 @@ Here's the full implementation. Note that the recursive algorithm is most effici ```swift // Karatsuba Multiplication -func karatsuba(_ num1: Int, by num2: Int) -> Int { - let num1Array = String(num1).characters - let num2Array = String(num2).characters + func karatsuba(_ num1: Int, by num2: Int) -> Int { + let num1String = String(num1) + let num2String = String(num2) - guard num1Array.count > 1 && num2Array.count > 1 else { - return num1*num2 + guard num1String.count > 1 && num2String.count > 1 else { + return multiply(num1, by: num2) } - let n = max(num1Array.count, num2Array.count) + let n = max(num1String.count, num2String.count) let nBy2 = n / 2 let a = num1 / 10^^nBy2 From 2d1d22316401f52ac6a08325c781e812e40542c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Afonso=20Gra=C3=A7a?= Date: Mon, 8 Oct 2018 20:20:30 +1100 Subject: [PATCH 070/271] [Swift 4.2] added tests --- .travis.yml | 1 + .../KaratsubaMultiplication.swift | 31 +- .../Tests/KaratsubaMultiplicationTests.swift | 17 + .../Tests/Tests.xcodeproj/project.pbxproj | 305 ++++++++++++++++++ .../xcshareddata/xcschemes/Tests.xcscheme | 56 ++++ .../Tests/Tests/Info.plist | 22 ++ .../contents.xcworkspacedata | 7 + 7 files changed, 434 insertions(+), 5 deletions(-) create mode 100644 Karatsuba Multiplication/Tests/KaratsubaMultiplicationTests.swift create mode 100644 Karatsuba Multiplication/Tests/Tests.xcodeproj/project.pbxproj create mode 100644 Karatsuba Multiplication/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme create mode 100644 Karatsuba Multiplication/Tests/Tests/Info.plist diff --git a/.travis.yml b/.travis.yml index edf1cf89f..56e205656 100644 --- a/.travis.yml +++ b/.travis.yml @@ -48,6 +48,7 @@ script: - xcodebuild test -project ./Treap/Treap/Treap.xcodeproj -scheme Tests | xcpretty -f `xcpretty-travis-formatter` - xcodebuild test -project ./Palindromes/Test/Test.xcodeproj -scheme Test | xcpretty -f `xcpretty-travis-formatter` - xcodebuild test -project ./Ternary\ Search\ Tree/Tests/Tests.xcodeproj -scheme Tests | xcpretty -f `xcpretty-travis-formatter` +- xcodebuild test -project ./Karatsuba\ Multiplication/Tests/Tests.xcodeproj -scheme Tests | xcpretty -f `xcpretty-travis-formatter` after_success: diff --git a/Karatsuba Multiplication/KaratsubaMultiplication.swift b/Karatsuba Multiplication/KaratsubaMultiplication.swift index a82e82658..3d14a243a 100644 --- a/Karatsuba Multiplication/KaratsubaMultiplication.swift +++ b/Karatsuba Multiplication/KaratsubaMultiplication.swift @@ -19,27 +19,48 @@ func ^^ (radix: Int, power: Int) -> Int { return Int(pow(Double(radix), Double(power))) } +// Long Multiplication - O(n^2) +func multiply(_ num1: Int, by num2: Int, base: Int = 10) -> Int { + let num1Array = String(num1).reversed().map { Int(String($0))! } + let num2Array = String(num2).reversed().map { Int(String($0))! } + + var product = Array(repeating: 0, count: num1Array.count + num2Array.count) + + for i in num1Array.indices { + var carry = 0 + for j in num2Array.indices { + product[i + j] += carry + num1Array[i] * num2Array[j] + carry = product[i + j] / base + product[i + j] %= base + } + product[i + num2Array.count] += carry + } + + return Int(product.reversed().map { String($0) }.reduce("", +))! +} + +// Karatsuba Multiplication - O(n^log2(3)) func karatsuba(_ num1: Int, by num2: Int) -> Int { let num1String = String(num1) let num2String = String(num2) - + guard num1String.count > 1 && num2String.count > 1 else { return multiply(num1, by: num2) } let n = max(num1String.count, num2String.count) let nBy2 = n / 2 - + let a = num1 / 10^^nBy2 let b = num1 % 10^^nBy2 let c = num2 / 10^^nBy2 let d = num2 % 10^^nBy2 - + let ac = karatsuba(a, by: c) let bd = karatsuba(b, by: d) let adPlusbc = karatsuba(a+b, by: c+d) - ac - bd - + let product = ac * 10^^(2 * nBy2) + adPlusbc * 10^^nBy2 + bd - + return product } diff --git a/Karatsuba Multiplication/Tests/KaratsubaMultiplicationTests.swift b/Karatsuba Multiplication/Tests/KaratsubaMultiplicationTests.swift new file mode 100644 index 000000000..379c9e812 --- /dev/null +++ b/Karatsuba Multiplication/Tests/KaratsubaMultiplicationTests.swift @@ -0,0 +1,17 @@ +// +// KaratsubaMultiplicationTests.swift +// Tests +// +// Created by Afonso Graça on 8/10/18. +// + +import XCTest + +final class KaratsubaMultiplicationTests: XCTestCase { + + func testReadmeExample() { + let subject = karatsuba(1234, by: 5678) + + XCTAssertEqual(subject, 7006652) + } +} diff --git a/Karatsuba Multiplication/Tests/Tests.xcodeproj/project.pbxproj b/Karatsuba Multiplication/Tests/Tests.xcodeproj/project.pbxproj new file mode 100644 index 000000000..ef23067ee --- /dev/null +++ b/Karatsuba Multiplication/Tests/Tests.xcodeproj/project.pbxproj @@ -0,0 +1,305 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 50; + objects = { + +/* Begin PBXBuildFile section */ + 6AF099AC216B54E200F69B16 /* KaratsubaMultiplication.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6AF099AB216B54E200F69B16 /* KaratsubaMultiplication.swift */; }; + 6AF099AE216B55A100F69B16 /* KaratsubaMultiplicationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6AF099AD216B55A100F69B16 /* KaratsubaMultiplicationTests.swift */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 6AF099A2216B54D500F69B16 /* Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = Tests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 6AF099A7216B54D500F69B16 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = Info.plist; path = Tests/Info.plist; sourceTree = SOURCE_ROOT; }; + 6AF099AB216B54E200F69B16 /* KaratsubaMultiplication.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = KaratsubaMultiplication.swift; path = ../KaratsubaMultiplication.swift; sourceTree = ""; }; + 6AF099AD216B55A100F69B16 /* KaratsubaMultiplicationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KaratsubaMultiplicationTests.swift; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 6AF0999F216B54D500F69B16 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 6AF09997216B545D00F69B16 = { + isa = PBXGroup; + children = ( + 6AF099AB216B54E200F69B16 /* KaratsubaMultiplication.swift */, + 6AF099A4216B54D500F69B16 /* Tests */, + 6AF099A3216B54D500F69B16 /* Products */, + ); + sourceTree = ""; + }; + 6AF099A3216B54D500F69B16 /* Products */ = { + isa = PBXGroup; + children = ( + 6AF099A2216B54D500F69B16 /* Tests.xctest */, + ); + name = Products; + sourceTree = ""; + }; + 6AF099A4216B54D500F69B16 /* Tests */ = { + isa = PBXGroup; + children = ( + 6AF099AD216B55A100F69B16 /* KaratsubaMultiplicationTests.swift */, + 6AF099A7216B54D500F69B16 /* Info.plist */, + ); + name = Tests; + sourceTree = SOURCE_ROOT; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 6AF099A1216B54D500F69B16 /* Tests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 6AF099A8216B54D500F69B16 /* Build configuration list for PBXNativeTarget "Tests" */; + buildPhases = ( + 6AF0999E216B54D500F69B16 /* Sources */, + 6AF0999F216B54D500F69B16 /* Frameworks */, + 6AF099A0216B54D500F69B16 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = Tests; + productName = Tests; + productReference = 6AF099A2216B54D500F69B16 /* Tests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 6AF09998216B545D00F69B16 /* Project object */ = { + isa = PBXProject; + attributes = { + LastSwiftUpdateCheck = 1000; + LastUpgradeCheck = 1000; + TargetAttributes = { + 6AF099A1216B54D500F69B16 = { + CreatedOnToolsVersion = 10.0; + }; + }; + }; + buildConfigurationList = 6AF0999B216B545D00F69B16 /* Build configuration list for PBXProject "Tests" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + ); + mainGroup = 6AF09997216B545D00F69B16; + productRefGroup = 6AF099A3216B54D500F69B16 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 6AF099A1216B54D500F69B16 /* Tests */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 6AF099A0216B54D500F69B16 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 6AF0999E216B54D500F69B16 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 6AF099AE216B55A100F69B16 /* KaratsubaMultiplicationTests.swift in Sources */, + 6AF099AC216B54E200F69B16 /* KaratsubaMultiplication.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + 6AF0999C216B545D00F69B16 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + }; + name = Debug; + }; + 6AF0999D216B545D00F69B16 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + }; + name = Release; + }; + 6AF099A9216B54D500F69B16 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "-"; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + INFOPLIST_FILE = Tests/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + "@loader_path/../Frameworks", + ); + MACOSX_DEPLOYMENT_TARGET = 10.14; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + ONLY_ACTIVE_ARCH = YES; + PRODUCT_BUNDLE_IDENTIFIER = swift.algorithm.club.Tests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = macosx; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 4.2; + }; + name = Debug; + }; + 6AF099AA216B54D500F69B16 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "-"; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + INFOPLIST_FILE = Tests/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + "@loader_path/../Frameworks", + ); + MACOSX_DEPLOYMENT_TARGET = 10.14; + MTL_ENABLE_DEBUG_INFO = NO; + MTL_FAST_MATH = YES; + PRODUCT_BUNDLE_IDENTIFIER = swift.algorithm.club.Tests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = macosx; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + SWIFT_VERSION = 4.2; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 6AF0999B216B545D00F69B16 /* Build configuration list for PBXProject "Tests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 6AF0999C216B545D00F69B16 /* Debug */, + 6AF0999D216B545D00F69B16 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 6AF099A8216B54D500F69B16 /* Build configuration list for PBXNativeTarget "Tests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 6AF099A9216B54D500F69B16 /* Debug */, + 6AF099AA216B54D500F69B16 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 6AF09998216B545D00F69B16 /* Project object */; +} diff --git a/Karatsuba Multiplication/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme b/Karatsuba Multiplication/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme new file mode 100644 index 000000000..1288fd9a8 --- /dev/null +++ b/Karatsuba Multiplication/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme @@ -0,0 +1,56 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Karatsuba Multiplication/Tests/Tests/Info.plist b/Karatsuba Multiplication/Tests/Tests/Info.plist new file mode 100644 index 000000000..6c40a6cd0 --- /dev/null +++ b/Karatsuba Multiplication/Tests/Tests/Info.plist @@ -0,0 +1,22 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + BNDL + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + + diff --git a/swift-algorithm-club.xcworkspace/contents.xcworkspacedata b/swift-algorithm-club.xcworkspace/contents.xcworkspacedata index 142713e62..9305ae37c 100644 --- a/swift-algorithm-club.xcworkspace/contents.xcworkspacedata +++ b/swift-algorithm-club.xcworkspace/contents.xcworkspacedata @@ -1472,6 +1472,13 @@ + + + + Date: Mon, 8 Oct 2018 20:31:20 +1100 Subject: [PATCH 071/271] [Swift 4.2] Update Fizz Buzz There was no need to update the source code, simply removed the code snippet. --- Fizz Buzz/FizzBuzz.playground/Contents.swift | 5 +---- .../xcshareddata/IDEWorkspaceChecks.plist | 8 ++++++++ 2 files changed, 9 insertions(+), 4 deletions(-) create mode 100644 Fizz Buzz/FizzBuzz.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist diff --git a/Fizz Buzz/FizzBuzz.playground/Contents.swift b/Fizz Buzz/FizzBuzz.playground/Contents.swift index 37acdab61..ae966bbcc 100644 --- a/Fizz Buzz/FizzBuzz.playground/Contents.swift +++ b/Fizz Buzz/FizzBuzz.playground/Contents.swift @@ -1,7 +1,4 @@ -// last checked with Xcode 9.0b4 -#if swift(>=4.0) -print("Hello, Swift 4!") -#endif +// last checked with Xcode 10.0 (10A255) func fizzBuzz(_ numberOfTurns: Int) { for i in 1...numberOfTurns { diff --git a/Fizz Buzz/FizzBuzz.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Fizz Buzz/FizzBuzz.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/Fizz Buzz/FizzBuzz.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + From 409e85fdc8968230758ef703804f51956dc524a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9F=D0=B0=D0=BD=D0=BA=D0=BE=D0=B2=D0=B0=20=D0=9C=D0=B0?= =?UTF-8?q?=D1=80=D0=B8=D1=8F=20=D0=92=D0=B8=D1=82=D0=B0=D0=BB=D1=8C=D0=B5?= =?UTF-8?q?=D0=B2=D0=BD=D0=B0?= Date: Mon, 8 Oct 2018 21:49:03 +0700 Subject: [PATCH 072/271] [Swift 4.2] Update Convex Hull --- .../Convex Hull.xcodeproj/project.pbxproj | 26 +++++++++++++++---- .../xcshareddata/xcschemes/Tests.xcscheme | 4 +-- .../AppIcon.appiconset/Contents.json | 5 ++++ Convex Hull/Convex Hull/View.swift | 4 +-- 4 files changed, 29 insertions(+), 10 deletions(-) diff --git a/Convex Hull/Convex Hull.xcodeproj/project.pbxproj b/Convex Hull/Convex Hull.xcodeproj/project.pbxproj index c11cbf4d6..27ca4eb25 100644 --- a/Convex Hull/Convex Hull.xcodeproj/project.pbxproj +++ b/Convex Hull/Convex Hull.xcodeproj/project.pbxproj @@ -139,7 +139,7 @@ isa = PBXProject; attributes = { LastSwiftUpdateCheck = 0900; - LastUpgradeCheck = 0820; + LastUpgradeCheck = 1000; ORGANIZATIONNAME = Workmoose; TargetAttributes = { 1CB6142C1F89456C00A14493 = { @@ -254,7 +254,7 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = com.mnespor.Tests; PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 4.0; + SWIFT_VERSION = 4.2; TARGETED_DEVICE_FAMILY = "1,2"; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Convex Hull.app/Convex Hull"; }; @@ -281,7 +281,7 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = com.mnespor.Tests; PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 4.0; + SWIFT_VERSION = 4.2; TARGETED_DEVICE_FAMILY = "1,2"; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Convex Hull.app/Convex Hull"; }; @@ -296,15 +296,23 @@ CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_DOCUMENTATION_COMMENTS = YES; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; @@ -346,15 +354,23 @@ CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_DOCUMENTATION_COMMENTS = YES; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; @@ -389,7 +405,7 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "workmoose.Convex-Hull"; PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 4.0; + SWIFT_VERSION = 4.2; }; name = Debug; }; @@ -402,7 +418,7 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "workmoose.Convex-Hull"; PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 4.0; + SWIFT_VERSION = 4.2; }; name = Release; }; diff --git a/Convex Hull/Convex Hull.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme b/Convex Hull/Convex Hull.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme index 1f93a0c4f..8f04a0f51 100644 --- a/Convex Hull/Convex Hull.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme +++ b/Convex Hull/Convex Hull.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme @@ -1,6 +1,6 @@ Date: Mon, 8 Oct 2018 19:30:25 -0300 Subject: [PATCH 073/271] removed duplicate implementation --- .../MyPlayground.playground/Contents.swift | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/Bubble Sort/MyPlayground.playground/Contents.swift b/Bubble Sort/MyPlayground.playground/Contents.swift index 16466e0bc..8d27d801e 100644 --- a/Bubble Sort/MyPlayground.playground/Contents.swift +++ b/Bubble Sort/MyPlayground.playground/Contents.swift @@ -1,22 +1,5 @@ import Foundation -public func BubbleSort (_ elements: [T]) -> [T] where T: Comparable { - var array = elements - - for i in 0.. Date: Mon, 8 Oct 2018 19:30:58 -0300 Subject: [PATCH 074/271] changed tab width to 2 spaces instead of 4 --- .../Sources/BubbleSort.swift | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/Bubble Sort/MyPlayground.playground/Sources/BubbleSort.swift b/Bubble Sort/MyPlayground.playground/Sources/BubbleSort.swift index 5ce18ef9b..9c091b661 100644 --- a/Bubble Sort/MyPlayground.playground/Sources/BubbleSort.swift +++ b/Bubble Sort/MyPlayground.playground/Sources/BubbleSort.swift @@ -26,17 +26,17 @@ import Foundation /// - Parameter elements: the array to be sorted /// - Returns: an array with the same elements but in order public func BubbleSort (_ elements: [T]) -> [T] where T: Comparable { - var array = elements - - for i in 0.. Date: Mon, 8 Oct 2018 20:16:55 -0300 Subject: [PATCH 075/271] updated readme to conform with changes requested --- Bubble Sort/README.markdown | 75 +++++++++++++++++++++++++++++-------- 1 file changed, 59 insertions(+), 16 deletions(-) diff --git a/Bubble Sort/README.markdown b/Bubble Sort/README.markdown index 80161ce56..e55129d93 100644 --- a/Bubble Sort/README.markdown +++ b/Bubble Sort/README.markdown @@ -1,6 +1,6 @@ # Bubble Sort -Bubble sort is a sorting algorithm that is implemented by starting in the beginning of the array and swapping the first two elements only if the first element is greater than the second element. This comparison is then moved onto the next pair and so on and so forth. This is done until the array is completely sorted. The smaller items slowly “bubble” up to the beginning of the array.Sometimes this algorithm is refered as Sinking sort, due to the larger, or heavier elements sinking to the end of the array. +Bubble sort is a sorting algorithm that is implemented by starting in the beginning of the array and swapping the first two elements only if the first element is greater than the second element. This comparison is then moved onto the next pair and so on and so forth. This is done until the array is completely sorted. The smaller items slowly “bubble” up to the beginning of the array. Sometimes this algorithm is refered as Sinking sort, due to the larger, or heavier elements sinking to the end of the array. ##### Runtime: - Average: O(N^2) @@ -16,6 +16,10 @@ The implementation will not be shown as the average and worst runtimes show that Bubble sort is a very simple sorting algorithm, it consists in comparing pairs of adjacent elements in the array, if the first element is larger, swap them, otherwise, you do nothing and go for the next comparison. This is accomplished by looking through the array `n` times, `n` being the amount of elements in the array. +![animated gif of the bubble sort algorithm](https://s3.amazonaws.com/codecademy-content/programs/tdd-js/articles/BubbleSort.gif) + +This GIF shows a inverted implementation than + #### Example Let us take the array `[5, 1, 4, 2, 8]`, and sort the array from lowest number to greatest number using bubble sort. In each step, elements written in bold are being compared. Three passes will be required. @@ -52,13 +56,13 @@ This is the same for the forth and fifth passes. #### Code ```swift for i in 0.. [ **1 5** 4 2 8 ], Swaps since 5 > 1 + +[ 1 **5 4** 2 8 ] -> [ 1 **4 5** 2 8 ], Swap since 5 > 4 + +[ 1 4 **5 2** 8 ] -> [ 1 4 **2 5** 8 ], Swap since 5 > 2 + +[ 1 4 2 **5 8** ] -> [ 1 4 2 **5 8** ], Now, since these elements are already in order (8 > 5), algorithm does not swap them. + +*by the end of the first pass, the last element is guaranteed to be the largest* + +##### Second Pass +[ **1 4** 2 5 8 ] -> [ **1 4** 2 5 8 ] + +[ 1 **4 2** 5 8 ] -> [ 1 **2 4** 5 8 ], Swap since 4 > 2 + +[ 1 2 **4 5** 8 ] -> [ 1 2 **4 5** 8 ], As the first loop has occured once, the inner loop stops here, not comparing 5 with 8 + +##### Third Pass +[ **1 2** 4 5 8 ] -> [ **1 2** 4 5 8 ] + +[ 1 **2 4** 5 8 ] -> [ 1 **2 4** 5 8 ] again, stoping one comparison short + +##### Fourth Pass +[ **1 2** 4 5 8 ] -> [ **1 2** 4 5 8 ] + +There is no Fifth pass + +#### Conclusion + +Even with the proposed optimizations, this is still a terribly inefficient sorting algorithm. A good alternative is [Merge Sort](), that not only is better performing, has a similar degree of dificulty to implement. + +*Updated for the Swift Algorithm Club by Julio Brazil* + +##### Supporting Links +[Code Pumpkin](https://codepumpkin.com/bubble-sort/) +[Wikipedia](https://en.wikipedia.org/wiki/Bubble_sort) +[GeeksforGeeks](https://www.geeksforgeeks.org/bubble-sort/) From 39971b49661a7179117511ddfc6c79e1bde12378 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=95=D0=BA=D0=B0=D1=82=D0=B5=D1=80=D0=B8=D0=BD=D0=B0=20?= =?UTF-8?q?=D0=91=D0=B0=D1=82=D0=B5=D0=B5=D0=B2=D0=B0?= Date: Wed, 10 Oct 2018 22:39:38 +0300 Subject: [PATCH 076/271] [Swift 4.2] Update Boyer-Moore-Horspool --- .../BoyerMooreHorspool.playground/Contents.swift | 6 +++--- .../xcshareddata/IDEWorkspaceChecks.plist | 8 ++++++++ .../BoyerMooreHorspool.playground/timeline.xctimeline | 6 +++--- Boyer-Moore-Horspool/BoyerMooreHorspool.swift | 6 +++--- 4 files changed, 17 insertions(+), 9 deletions(-) create mode 100644 Boyer-Moore-Horspool/BoyerMooreHorspool.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist diff --git a/Boyer-Moore-Horspool/BoyerMooreHorspool.playground/Contents.swift b/Boyer-Moore-Horspool/BoyerMooreHorspool.playground/Contents.swift index e88a1b93d..5817cc41f 100644 --- a/Boyer-Moore-Horspool/BoyerMooreHorspool.playground/Contents.swift +++ b/Boyer-Moore-Horspool/BoyerMooreHorspool.playground/Contents.swift @@ -16,13 +16,13 @@ extension String { func index(of pattern: String, usingHorspoolImprovement: Bool = false) -> Index? { // Cache the length of the search pattern because we're going to // use it a few times and it's expensive to calculate. - let patternLength = pattern.characters.count - guard patternLength > 0, patternLength <= characters.count else { return nil } + let patternLength = pattern.count + guard patternLength > 0, patternLength <= count else { return nil } // Make the skip table. This table determines how far we skip ahead // when a character from the pattern is found. var skipTable = [Character: Int]() - for (i, c) in pattern.characters.enumerated() { + for (i, c) in pattern.enumerated() { skipTable[c] = patternLength - i - 1 } diff --git a/Boyer-Moore-Horspool/BoyerMooreHorspool.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Boyer-Moore-Horspool/BoyerMooreHorspool.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/Boyer-Moore-Horspool/BoyerMooreHorspool.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/Boyer-Moore-Horspool/BoyerMooreHorspool.playground/timeline.xctimeline b/Boyer-Moore-Horspool/BoyerMooreHorspool.playground/timeline.xctimeline index 89bc76f90..2688d72c1 100644 --- a/Boyer-Moore-Horspool/BoyerMooreHorspool.playground/timeline.xctimeline +++ b/Boyer-Moore-Horspool/BoyerMooreHorspool.playground/timeline.xctimeline @@ -3,17 +3,17 @@ version = "3.0"> diff --git a/Boyer-Moore-Horspool/BoyerMooreHorspool.swift b/Boyer-Moore-Horspool/BoyerMooreHorspool.swift index af8aea9d9..dbd738740 100644 --- a/Boyer-Moore-Horspool/BoyerMooreHorspool.swift +++ b/Boyer-Moore-Horspool/BoyerMooreHorspool.swift @@ -9,13 +9,13 @@ extension String { func index(of pattern: String, usingHorspoolImprovement: Bool = false) -> Index? { // Cache the length of the search pattern because we're going to // use it a few times and it's expensive to calculate. - let patternLength = pattern.characters.count - guard patternLength > 0, patternLength <= characters.count else { return nil } + let patternLength = pattern.count + guard patternLength > 0, patternLength <= count else { return nil } // Make the skip table. This table determines how far we skip ahead // when a character from the pattern is found. var skipTable = [Character: Int]() - for (i, c) in pattern.characters.enumerated() { + for (i, c) in pattern.enumerated() { skipTable[c] = patternLength - i - 1 } From 8e6c983cd0c5ae26a68531bb54521b85f3926120 Mon Sep 17 00:00:00 2001 From: Varun Date: Thu, 11 Oct 2018 13:41:40 +0530 Subject: [PATCH 077/271] updated LinkedList.playground to swift 4.2 --- Linked List/LinkedList.playground/Contents.swift | 4 ---- Linked List/LinkedList.playground/contents.xcplayground | 2 +- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/Linked List/LinkedList.playground/Contents.swift b/Linked List/LinkedList.playground/Contents.swift index cfa3a8b45..894b2d37f 100644 --- a/Linked List/LinkedList.playground/Contents.swift +++ b/Linked List/LinkedList.playground/Contents.swift @@ -3,10 +3,6 @@ // For best results, don't forget to select "Show Rendered Markup" from XCode's "Editor" menu //: Linked List Class Declaration: -// last checked with Xcode 9.0b4 -#if swift(>=4.0) -print("Hello, Swift 4!") -#endif public final class LinkedList { diff --git a/Linked List/LinkedList.playground/contents.xcplayground b/Linked List/LinkedList.playground/contents.xcplayground index 3de2b51ba..5e28f2dd0 100644 --- a/Linked List/LinkedList.playground/contents.xcplayground +++ b/Linked List/LinkedList.playground/contents.xcplayground @@ -1,4 +1,4 @@ - + \ No newline at end of file From 3f0ee826265621d22205316a3f52f22d7e5ee39f Mon Sep 17 00:00:00 2001 From: Bruno Scheele Date: Thu, 11 Oct 2018 14:17:34 +0200 Subject: [PATCH 078/271] Update to Swift 4.2. Also removed unused Tests group from project. --- .../project.pbxproj | 22 ++++++++----------- .../xcshareddata/IDEWorkspaceChecks.plist | 8 +++++++ 2 files changed, 17 insertions(+), 13 deletions(-) create mode 100644 DiningPhilosophers/DiningPhilosophers.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist diff --git a/DiningPhilosophers/DiningPhilosophers.xcodeproj/project.pbxproj b/DiningPhilosophers/DiningPhilosophers.xcodeproj/project.pbxproj index ecb060026..97f3c4847 100755 --- a/DiningPhilosophers/DiningPhilosophers.xcodeproj/project.pbxproj +++ b/DiningPhilosophers/DiningPhilosophers.xcodeproj/project.pbxproj @@ -27,13 +27,6 @@ /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ - OBJ_10 /* Tests */ = { - isa = PBXGroup; - children = ( - ); - path = Tests; - sourceTree = ""; - }; OBJ_11 /* Products */ = { isa = PBXGroup; children = ( @@ -42,15 +35,13 @@ name = Products; sourceTree = BUILT_PRODUCTS_DIR; }; - OBJ_5 /* */ = { + OBJ_5 = { isa = PBXGroup; children = ( OBJ_6 /* Package.swift */, OBJ_7 /* Sources */, - OBJ_10 /* Tests */, OBJ_11 /* Products */, ); - name = ""; sourceTree = ""; }; OBJ_7 /* Sources */ = { @@ -96,6 +87,11 @@ isa = PBXProject; attributes = { LastUpgradeCheck = 9999; + TargetAttributes = { + OBJ_13 = { + LastSwiftMigration = 1000; + }; + }; }; buildConfigurationList = OBJ_2 /* Build configuration list for PBXProject "DiningPhilosophers" */; compatibilityVersion = "Xcode 3.2"; @@ -104,7 +100,7 @@ knownRegions = ( en, ); - mainGroup = OBJ_5 /* */; + mainGroup = OBJ_5; productRefGroup = OBJ_11 /* Products */; projectDirPath = ""; projectRoot = ""; @@ -139,7 +135,7 @@ SWIFT_ACTIVE_COMPILATION_CONDITIONS = SWIFT_PACKAGE; SWIFT_FORCE_DYNAMIC_LINK_STDLIB = YES; SWIFT_FORCE_STATIC_LINK_STDLIB = NO; - SWIFT_VERSION = 4.0; + SWIFT_VERSION = 4.2; TARGET_NAME = DiningPhilosophers; }; name = Debug; @@ -157,7 +153,7 @@ SWIFT_ACTIVE_COMPILATION_CONDITIONS = SWIFT_PACKAGE; SWIFT_FORCE_DYNAMIC_LINK_STDLIB = YES; SWIFT_FORCE_STATIC_LINK_STDLIB = NO; - SWIFT_VERSION = 4.0; + SWIFT_VERSION = 4.2; TARGET_NAME = DiningPhilosophers; }; name = Release; diff --git a/DiningPhilosophers/DiningPhilosophers.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/DiningPhilosophers/DiningPhilosophers.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/DiningPhilosophers/DiningPhilosophers.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + From 6c48b3d493b4e6f023b006871f58fbe485db96b1 Mon Sep 17 00:00:00 2001 From: Bruno Scheele Date: Thu, 11 Oct 2018 14:18:45 +0200 Subject: [PATCH 079/271] Add README.md to project. This makes it easier to read along with the code. --- DiningPhilosophers/DiningPhilosophers.xcodeproj/project.pbxproj | 2 ++ 1 file changed, 2 insertions(+) diff --git a/DiningPhilosophers/DiningPhilosophers.xcodeproj/project.pbxproj b/DiningPhilosophers/DiningPhilosophers.xcodeproj/project.pbxproj index 97f3c4847..7699219de 100755 --- a/DiningPhilosophers/DiningPhilosophers.xcodeproj/project.pbxproj +++ b/DiningPhilosophers/DiningPhilosophers.xcodeproj/project.pbxproj @@ -11,6 +11,7 @@ /* End PBXBuildFile section */ /* Begin PBXFileReference section */ + 232D7939216F76F700831A74 /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = ""; }; OBJ_12 /* DiningPhilosophers */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; path = DiningPhilosophers; sourceTree = BUILT_PRODUCTS_DIR; }; OBJ_6 /* Package.swift */ = {isa = PBXFileReference; explicitFileType = sourcecode.swift; path = Package.swift; sourceTree = ""; }; OBJ_9 /* main.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = main.swift; sourceTree = ""; }; @@ -38,6 +39,7 @@ OBJ_5 = { isa = PBXGroup; children = ( + 232D7939216F76F700831A74 /* README.md */, OBJ_6 /* Package.swift */, OBJ_7 /* Sources */, OBJ_11 /* Products */, From f2c04f7ac0ed2634221eca58ed303e3a3b239cd9 Mon Sep 17 00:00:00 2001 From: Bruno Scheele Date: Thu, 11 Oct 2018 14:18:54 +0200 Subject: [PATCH 080/271] Add credit to README.md. --- DiningPhilosophers/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/DiningPhilosophers/README.md b/DiningPhilosophers/README.md index cd9d86154..aed9dfe59 100755 --- a/DiningPhilosophers/README.md +++ b/DiningPhilosophers/README.md @@ -57,3 +57,4 @@ A background DispatchQueue is then used to let any Philosopher run asyncrounosly Dining Philosophers on Wikipedia https://en.wikipedia.org/wiki/Dining_philosophers_problem Written for Swift Algorithm Club by Jacopo Mangiavacchi +Swift 4.2 check by Bruno Scheele From eeb116e4073a0b1a0a9d13701bbe27d29e1ec6bb Mon Sep 17 00:00:00 2001 From: Bruno Scheele Date: Thu, 11 Oct 2018 14:26:17 +0200 Subject: [PATCH 081/271] Update to Swift 4.2. --- Red-Black Tree/RedBlackTree.playground/Contents.swift | 5 ----- .../xcshareddata/IDEWorkspaceChecks.plist | 8 ++++++++ 2 files changed, 8 insertions(+), 5 deletions(-) create mode 100644 Red-Black Tree/RedBlackTree.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist diff --git a/Red-Black Tree/RedBlackTree.playground/Contents.swift b/Red-Black Tree/RedBlackTree.playground/Contents.swift index f14f18e58..d1133bc98 100644 --- a/Red-Black Tree/RedBlackTree.playground/Contents.swift +++ b/Red-Black Tree/RedBlackTree.playground/Contents.swift @@ -2,11 +2,6 @@ // Test for the RedBlackTree implementation provided in the Source folder of this Playground import Foundation -// last checked with Xcode 9.0b4 -#if swift(>=4.0) -print("Hello, Swift 4!") -#endif - let redBlackTree = RedBlackTree() let randomMax = Double(0x10000000) diff --git a/Red-Black Tree/RedBlackTree.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Red-Black Tree/RedBlackTree.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/Red-Black Tree/RedBlackTree.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + From af9a6564f87da3390d9c0287995ba213f47c94ad Mon Sep 17 00:00:00 2001 From: Bruno Scheele Date: Thu, 11 Oct 2018 14:26:34 +0200 Subject: [PATCH 082/271] Add credit to README.md. --- Red-Black Tree/README.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Red-Black Tree/README.markdown b/Red-Black Tree/README.markdown index 74fffa415..fd6c4db18 100644 --- a/Red-Black Tree/README.markdown +++ b/Red-Black Tree/README.markdown @@ -186,4 +186,4 @@ The overall runtime of delete is O(log n). ## Resources: [CLRS] T. Cormen, C. Leiserson, R. Rivest, and C. Stein. "Introduction to Algorithms", Third Edition. 2009 -*Written for Swift Algorithm Club by Ute Schiehlen. Updated from Jaap Wijnen and Ashwin Raghuraman's contributions.* +*Written for Swift Algorithm Club by Ute Schiehlen. Updated from Jaap Wijnen and Ashwin Raghuraman's contributions. Swift 4.2 check by Bruno Scheele.* From d3d382f1d2f76c91a14a9b61b02375f7c6388265 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=95=D0=BA=D0=B0=D1=82=D0=B5=D1=80=D0=B8=D0=BD=D0=B0=20?= =?UTF-8?q?=D0=91=D0=B0=D1=82=D0=B5=D0=B5=D0=B2=D0=B0?= Date: Fri, 12 Oct 2018 23:06:22 +0300 Subject: [PATCH 083/271] Fix HarversineDistance pi parameter in "Converts from degrees to radians" --- HaversineDistance/HaversineDistance.playground/Contents.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/HaversineDistance/HaversineDistance.playground/Contents.swift b/HaversineDistance/HaversineDistance.playground/Contents.swift index 5b3f591d6..7aa686645 100644 --- a/HaversineDistance/HaversineDistance.playground/Contents.swift +++ b/HaversineDistance/HaversineDistance.playground/Contents.swift @@ -16,7 +16,7 @@ func haversineDinstance(la1: Double, lo1: Double, la2: Double, lo2: Double, radi // Converts from degrees to radians let dToR = { (angle: Double) -> Double in - return (angle / 360) * 2 * M_PI + return (angle / 360) * 2 * .pi } let lat1 = dToR(la1) From acb21c32df8cc6c2ba8c153497902c24a661fff4 Mon Sep 17 00:00:00 2001 From: Nick Thompson Date: Fri, 12 Oct 2018 17:18:55 -0400 Subject: [PATCH 084/271] Updated MST to Swift 4.2 --- .../MinimumSpanningTree.playground/Contents.swift | 5 ----- .../xcshareddata/IDEWorkspaceChecks.plist | 8 ++++++++ 2 files changed, 8 insertions(+), 5 deletions(-) create mode 100644 Minimum Spanning Tree/MinimumSpanningTree.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist diff --git a/Minimum Spanning Tree/MinimumSpanningTree.playground/Contents.swift b/Minimum Spanning Tree/MinimumSpanningTree.playground/Contents.swift index c4f0a811b..7e3532429 100644 --- a/Minimum Spanning Tree/MinimumSpanningTree.playground/Contents.swift +++ b/Minimum Spanning Tree/MinimumSpanningTree.playground/Contents.swift @@ -3,11 +3,6 @@ Kruskal's and Prim's algorithms. */ -// last checked with Xcode 9.0b4 -#if swift(>=4.0) -print("Hello, Swift 4!") -#endif - func minimumSpanningTreeKruskal(graph: Graph) -> (cost: Int, tree: Graph) { var cost: Int = 0 var tree = Graph() diff --git a/Minimum Spanning Tree/MinimumSpanningTree.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Minimum Spanning Tree/MinimumSpanningTree.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/Minimum Spanning Tree/MinimumSpanningTree.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + From e0c6676601b6de0b093d3a171bf7497c73947522 Mon Sep 17 00:00:00 2001 From: Nick Thompson Date: Fri, 12 Oct 2018 17:37:17 -0400 Subject: [PATCH 085/271] Updated MST (Unweighted) to Swift 4.2 --- .../Contents.swift | 5 ----- .../xcshareddata/IDEWorkspaceChecks.plist | 8 ++++++++ 2 files changed, 8 insertions(+), 5 deletions(-) create mode 100644 Minimum Spanning Tree (Unweighted)/MinimumSpanningTree.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist diff --git a/Minimum Spanning Tree (Unweighted)/MinimumSpanningTree.playground/Pages/Minimum spanning tree example.xcplaygroundpage/Contents.swift b/Minimum Spanning Tree (Unweighted)/MinimumSpanningTree.playground/Pages/Minimum spanning tree example.xcplaygroundpage/Contents.swift index 65aa9fbc4..8ad04379c 100644 --- a/Minimum Spanning Tree (Unweighted)/MinimumSpanningTree.playground/Pages/Minimum spanning tree example.xcplaygroundpage/Contents.swift +++ b/Minimum Spanning Tree (Unweighted)/MinimumSpanningTree.playground/Pages/Minimum spanning tree example.xcplaygroundpage/Contents.swift @@ -1,8 +1,3 @@ -// last checked with Xcode 9.0b4 -#if swift(>=4.0) -print("Hello, Swift 4!") -#endif - func breadthFirstSearchMinimumSpanningTree(_ graph: Graph, source: Node) -> Graph { let minimumSpanningTree = graph.duplicate() diff --git a/Minimum Spanning Tree (Unweighted)/MinimumSpanningTree.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Minimum Spanning Tree (Unweighted)/MinimumSpanningTree.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/Minimum Spanning Tree (Unweighted)/MinimumSpanningTree.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + From 45cca894960b5aab35f8e675c1e2066025e7df91 Mon Sep 17 00:00:00 2001 From: Nick Thompson Date: Fri, 12 Oct 2018 17:40:24 -0400 Subject: [PATCH 086/271] Updated MST (Unweighted) tests to Swift 4.2 --- .../Tests/Tests.xcodeproj/project.pbxproj | 31 ++++++++++++++++--- .../xcshareddata/IDEWorkspaceChecks.plist | 8 +++++ .../xcshareddata/xcschemes/Tests.xcscheme | 2 +- 3 files changed, 36 insertions(+), 5 deletions(-) create mode 100644 Minimum Spanning Tree (Unweighted)/Tests/Tests.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist diff --git a/Minimum Spanning Tree (Unweighted)/Tests/Tests.xcodeproj/project.pbxproj b/Minimum Spanning Tree (Unweighted)/Tests/Tests.xcodeproj/project.pbxproj index a066b7a71..afb3b8acb 100644 --- a/Minimum Spanning Tree (Unweighted)/Tests/Tests.xcodeproj/project.pbxproj +++ b/Minimum Spanning Tree (Unweighted)/Tests/Tests.xcodeproj/project.pbxproj @@ -89,12 +89,12 @@ isa = PBXProject; attributes = { LastSwiftUpdateCheck = 0720; - LastUpgradeCheck = 0720; + LastUpgradeCheck = 1000; ORGANIZATIONNAME = "Swift Algorithm Club"; TargetAttributes = { 7B2BBC7F1C779D720067B71D = { CreatedOnToolsVersion = 7.2; - LastSwiftMigration = 0820; + LastSwiftMigration = 1000; }; }; }; @@ -149,13 +149,23 @@ CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_IDENTITY = "-"; @@ -193,13 +203,23 @@ CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_IDENTITY = "-"; @@ -218,6 +238,7 @@ MACOSX_DEPLOYMENT_TARGET = 10.11; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = macosx; + SWIFT_COMPILATION_MODE = wholemodule; }; name = Release; }; @@ -231,7 +252,8 @@ PRODUCT_BUNDLE_IDENTIFIER = swift.algorithm.club.Tests; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 3.0; + SWIFT_SWIFT3_OBJC_INFERENCE = Default; + SWIFT_VERSION = 4.2; }; name = Debug; }; @@ -244,7 +266,8 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = swift.algorithm.club.Tests; PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 3.0; + SWIFT_SWIFT3_OBJC_INFERENCE = Default; + SWIFT_VERSION = 4.2; }; name = Release; }; diff --git a/Minimum Spanning Tree (Unweighted)/Tests/Tests.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Minimum Spanning Tree (Unweighted)/Tests/Tests.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/Minimum Spanning Tree (Unweighted)/Tests/Tests.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/Minimum Spanning Tree (Unweighted)/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme b/Minimum Spanning Tree (Unweighted)/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme index 8ef8d8581..afd69e6a7 100644 --- a/Minimum Spanning Tree (Unweighted)/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme +++ b/Minimum Spanning Tree (Unweighted)/Tests/Tests.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme @@ -1,6 +1,6 @@ Date: Sat, 13 Oct 2018 10:59:37 +0300 Subject: [PATCH 087/271] update Huffman Coding to Swift 4.2 --- Huffman Coding/Huffman.playground/Contents.swift | 5 ----- 1 file changed, 5 deletions(-) diff --git a/Huffman Coding/Huffman.playground/Contents.swift b/Huffman Coding/Huffman.playground/Contents.swift index 6242ad272..2d59908e9 100644 --- a/Huffman Coding/Huffman.playground/Contents.swift +++ b/Huffman Coding/Huffman.playground/Contents.swift @@ -1,10 +1,5 @@ //: Playground - noun: a place where people can play -// last checked with Xcode 9.0b4 -#if swift(>=4.0) -print("Hello, Swift 4!") -#endif - import Foundation let s1 = "so much words wow many compression" From 85738885f0ec2e2f6041eb8545a4cfa99233e783 Mon Sep 17 00:00:00 2001 From: Viktor Sokolov Date: Sat, 13 Oct 2018 11:21:15 +0300 Subject: [PATCH 088/271] Update Quad Tree to Swift 4.2 --- QuadTree/QuadTree.playground/Contents.swift | 5 ----- 1 file changed, 5 deletions(-) diff --git a/QuadTree/QuadTree.playground/Contents.swift b/QuadTree/QuadTree.playground/Contents.swift index f0d8cb2ef..ad8ee31f8 100644 --- a/QuadTree/QuadTree.playground/Contents.swift +++ b/QuadTree/QuadTree.playground/Contents.swift @@ -1,8 +1,3 @@ -// last checked with Xcode 9.0b5 -#if swift(>=4.0) -print("Hello, Swift 4!") -#endif - import Foundation let tree = QuadTree(rect: Rect(origin: Point(0, 0), size: Size(xLength: 10, yLength: 10))) From 61400ea88862429ea588cf07e396377ca485d9b0 Mon Sep 17 00:00:00 2001 From: Viktor Sokolov Date: Sat, 13 Oct 2018 11:31:57 +0300 Subject: [PATCH 089/271] Update Multiset to Swift 4.2 --- Multiset/Multiset.playground/Contents.swift | 4 ---- 1 file changed, 4 deletions(-) diff --git a/Multiset/Multiset.playground/Contents.swift b/Multiset/Multiset.playground/Contents.swift index b4f64ee1f..64b729df1 100644 --- a/Multiset/Multiset.playground/Contents.swift +++ b/Multiset/Multiset.playground/Contents.swift @@ -1,9 +1,5 @@ //: Playground - noun: a place where people can play -#if swift(>=4.0) - print("Hello, Swift 4!") -#endif - import Cocoa var set = Multiset() From bb9ae3b6629da9b837c4cf33f9dfd977b13a635d Mon Sep 17 00:00:00 2001 From: Viktor Sokolov Date: Sat, 13 Oct 2018 11:39:24 +0300 Subject: [PATCH 090/271] Update Monty Hall to Swift 4.2 --- Monty Hall Problem/MontyHall.playground/Contents.swift | 5 ----- 1 file changed, 5 deletions(-) diff --git a/Monty Hall Problem/MontyHall.playground/Contents.swift b/Monty Hall Problem/MontyHall.playground/Contents.swift index 4bfff2340..a809410c7 100644 --- a/Monty Hall Problem/MontyHall.playground/Contents.swift +++ b/Monty Hall Problem/MontyHall.playground/Contents.swift @@ -1,10 +1,5 @@ //: Playground - noun: a place where people can play -// last checked with Xcode 9.0b4 -#if swift(>=4.0) - print("Hello, Swift 4!") -#endif - import Foundation func random(_ n: Int) -> Int { From 33a50920ebefc92ce844d6f024e8c4a49f2eb3ef Mon Sep 17 00:00:00 2001 From: Viktor Sokolov Date: Sat, 13 Oct 2018 11:49:26 +0300 Subject: [PATCH 091/271] Update Ring Buffer to Swift 4.2 --- Ring Buffer/RingBuffer.playground/Contents.swift | 5 ----- 1 file changed, 5 deletions(-) diff --git a/Ring Buffer/RingBuffer.playground/Contents.swift b/Ring Buffer/RingBuffer.playground/Contents.swift index f9ddb9c99..adcf146b4 100644 --- a/Ring Buffer/RingBuffer.playground/Contents.swift +++ b/Ring Buffer/RingBuffer.playground/Contents.swift @@ -1,10 +1,5 @@ //: Playground - noun: a place where people can play -// last checked with Xcode 9.0b4 -#if swift(>=4.0) -print("Hello, Swift 4!") -#endif - public struct RingBuffer { fileprivate var array: [T?] fileprivate var readIndex = 0 From 2a2971800f986286b098928f0cce0199a749ba9e Mon Sep 17 00:00:00 2001 From: NORMANDY REAL Date: Sat, 13 Oct 2018 22:25:30 +0800 Subject: [PATCH 092/271] Migrate to Swift 4.2 --- Ordered Array/OrderedArray.playground/Contents.swift | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/Ordered Array/OrderedArray.playground/Contents.swift b/Ordered Array/OrderedArray.playground/Contents.swift index 5b6be6420..e48af22e2 100644 --- a/Ordered Array/OrderedArray.playground/Contents.swift +++ b/Ordered Array/OrderedArray.playground/Contents.swift @@ -1,9 +1,6 @@ //: Playground - noun: a place where people can play -// last checked with Xcode 9.0b4 -#if swift(>=4.0) -print("Hello, Swift 4!") -#endif + public struct OrderedArray { fileprivate var array = [T]() From 58af4187be04c17586a3bb37f30fd269bffd2692 Mon Sep 17 00:00:00 2001 From: Nick Thompson Date: Sat, 13 Oct 2018 10:32:59 -0400 Subject: [PATCH 093/271] Updated LRU Cache to Swift 4.2 --- LRU Cache/LRUCache.playground/Contents.swift | 5 ----- .../playground.xcworkspace/contents.xcworkspacedata | 7 +++++++ .../xcshareddata/IDEWorkspaceChecks.plist | 8 ++++++++ 3 files changed, 15 insertions(+), 5 deletions(-) create mode 100644 LRU Cache/LRUCache.playground/playground.xcworkspace/contents.xcworkspacedata create mode 100644 LRU Cache/LRUCache.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist diff --git a/LRU Cache/LRUCache.playground/Contents.swift b/LRU Cache/LRUCache.playground/Contents.swift index 2ebc03242..35dcc5d59 100644 --- a/LRU Cache/LRUCache.playground/Contents.swift +++ b/LRU Cache/LRUCache.playground/Contents.swift @@ -1,8 +1,3 @@ -// last checked with Xcode 9.0b4 -#if swift(>=4.0) -print("Hello, Swift 4!") -#endif - let cache = LRUCache(2) cache.set("a", val: 1) cache.set("b", val: 2) diff --git a/LRU Cache/LRUCache.playground/playground.xcworkspace/contents.xcworkspacedata b/LRU Cache/LRUCache.playground/playground.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..919434a62 --- /dev/null +++ b/LRU Cache/LRUCache.playground/playground.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/LRU Cache/LRUCache.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/LRU Cache/LRUCache.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/LRU Cache/LRUCache.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + From 4130f3502c344e0b43f09c0ba6cef0221ef1ff92 Mon Sep 17 00:00:00 2001 From: karolms Date: Sun, 14 Oct 2018 01:37:22 -0300 Subject: [PATCH 094/271] Updated Bit Set to Swift 4.2 --- Bit Set/BitSet.playground/Contents.swift | 4 ---- .../xcshareddata/IDEWorkspaceChecks.plist | 8 ++++++++ 2 files changed, 8 insertions(+), 4 deletions(-) create mode 100644 swift-algorithm-club.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist diff --git a/Bit Set/BitSet.playground/Contents.swift b/Bit Set/BitSet.playground/Contents.swift index 95253ea27..568202a33 100644 --- a/Bit Set/BitSet.playground/Contents.swift +++ b/Bit Set/BitSet.playground/Contents.swift @@ -1,9 +1,5 @@ //: Playground - noun: a place where people can play -// last checked with Xcode 9.0b4 -#if swift(>=4.0) -print("Hello, Swift 4!") -#endif // Create a bit set that stores 140 bits var bits = BitSet(size: 140) diff --git a/swift-algorithm-club.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/swift-algorithm-club.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/swift-algorithm-club.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + From d4d5b473774e68a24d3320865749d3dfe257da88 Mon Sep 17 00:00:00 2001 From: karolms Date: Sun, 14 Oct 2018 01:51:54 -0300 Subject: [PATCH 095/271] Updated Kth largest element to Swift 4.2 --- Kth Largest Element/kthLargest.playground/Contents.swift | 4 ---- 1 file changed, 4 deletions(-) diff --git a/Kth Largest Element/kthLargest.playground/Contents.swift b/Kth Largest Element/kthLargest.playground/Contents.swift index e6fca2ceb..a27dfce7d 100644 --- a/Kth Largest Element/kthLargest.playground/Contents.swift +++ b/Kth Largest Element/kthLargest.playground/Contents.swift @@ -1,9 +1,5 @@ //: Playground - noun: a place where people can play -// last checked with Xcode 9.0b4 -#if swift(>=4.0) -print("Hello, Swift 4!") -#endif let a = [5, 1, 3, 2, 7, 6, 4] From 75182345961675c51823a5d8ec514d85e91c7de8 Mon Sep 17 00:00:00 2001 From: karolms Date: Sun, 14 Oct 2018 02:02:21 -0300 Subject: [PATCH 096/271] Revert "Updated Bit Set to Swift 4.2" This reverts commit 4130f3502c344e0b43f09c0ba6cef0221ef1ff92. --- Bit Set/BitSet.playground/Contents.swift | 4 ++++ .../xcshareddata/IDEWorkspaceChecks.plist | 8 -------- 2 files changed, 4 insertions(+), 8 deletions(-) delete mode 100644 swift-algorithm-club.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist diff --git a/Bit Set/BitSet.playground/Contents.swift b/Bit Set/BitSet.playground/Contents.swift index 568202a33..95253ea27 100644 --- a/Bit Set/BitSet.playground/Contents.swift +++ b/Bit Set/BitSet.playground/Contents.swift @@ -1,5 +1,9 @@ //: Playground - noun: a place where people can play +// last checked with Xcode 9.0b4 +#if swift(>=4.0) +print("Hello, Swift 4!") +#endif // Create a bit set that stores 140 bits var bits = BitSet(size: 140) diff --git a/swift-algorithm-club.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/swift-algorithm-club.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist deleted file mode 100644 index 18d981003..000000000 --- a/swift-algorithm-club.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +++ /dev/null @@ -1,8 +0,0 @@ - - - - - IDEDidComputeMac32BitWarning - - - From f7b3996dd301816a66618fc497edb546706e68d0 Mon Sep 17 00:00:00 2001 From: karolms Date: Sun, 14 Oct 2018 02:09:18 -0300 Subject: [PATCH 097/271] Updated Knuth-Morris-Pratt to Swift 4.2 --- .../KnuthMorrisPratt.playground/Contents.swift | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/Knuth-Morris-Pratt/KnuthMorrisPratt.playground/Contents.swift b/Knuth-Morris-Pratt/KnuthMorrisPratt.playground/Contents.swift index 6609c9abe..9b4a50fa0 100644 --- a/Knuth-Morris-Pratt/KnuthMorrisPratt.playground/Contents.swift +++ b/Knuth-Morris-Pratt/KnuthMorrisPratt.playground/Contents.swift @@ -1,13 +1,8 @@ //: Playground - noun: a place where people can play -// last checked with Xcode 9.0b4 -#if swift(>=4.0) -print("Hello, Swift4!") -#endif - func ZetaAlgorithm(ptnr: String) -> [Int]? { - let pattern = Array(ptnr.characters) + let pattern = Array(ptnr) let patternLength: Int = pattern.count guard patternLength > 0 else { @@ -65,7 +60,7 @@ extension String { func indexesOf(ptnr: String) -> [Int]? { - let text = Array(self.characters) + let text = Array(self) let pattern = Array(ptnr.characters) let textLength: Int = text.count From 6c2aa24b0674a97e755bf8c0acf480d6e107e756 Mon Sep 17 00:00:00 2001 From: karolms Date: Sun, 14 Oct 2018 02:23:51 -0300 Subject: [PATCH 098/271] Updated AVL Tree to Swift 4.2 --- AVL Tree/AVLTree.playground/Contents.swift | 4 ---- 1 file changed, 4 deletions(-) diff --git a/AVL Tree/AVLTree.playground/Contents.swift b/AVL Tree/AVLTree.playground/Contents.swift index 04ef78d07..34c1e6ddd 100644 --- a/AVL Tree/AVLTree.playground/Contents.swift +++ b/AVL Tree/AVLTree.playground/Contents.swift @@ -1,9 +1,5 @@ //: Playground - noun: a place where people can play -// last checked with Xcode 9.0b4 -#if swift(>=4.0) -print("Hello, Swift 4!") -#endif let tree = AVLTree() From 6536cd7af049eec810033f9611e6e8e5767a8a54 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Afonso=20Gra=C3=A7a?= Date: Mon, 15 Oct 2018 13:17:08 +1100 Subject: [PATCH 099/271] fix indentation typos in the README.md --- Karatsuba Multiplication/README.markdown | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Karatsuba Multiplication/README.markdown b/Karatsuba Multiplication/README.markdown index 3a48ed39d..aef0d744a 100644 --- a/Karatsuba Multiplication/README.markdown +++ b/Karatsuba Multiplication/README.markdown @@ -71,12 +71,12 @@ Here's the full implementation. Note that the recursive algorithm is most effici ```swift // Karatsuba Multiplication - func karatsuba(_ num1: Int, by num2: Int) -> Int { +func karatsuba(_ num1: Int, by num2: Int) -> Int { let num1String = String(num1) let num2String = String(num2) guard num1String.count > 1 && num2String.count > 1 else { - return multiply(num1, by: num2) + return multiply(num1, by: num2) } let n = max(num1String.count, num2String.count) From 32fe7e84c0378daacf3e4048cf2f4d55bdb22c65 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Afonso=20Gra=C3=A7a?= Date: Mon, 15 Oct 2018 13:25:42 +1100 Subject: [PATCH 100/271] [Swift 4.2] Update Miller-Rabin Primality Test References #748 There were no necessary code changes for Swift 4.2. Removed the snippet requested --- .../MRPrimality.playground/Contents.swift | 5 ----- .../playground.xcworkspace/contents.xcworkspacedata | 4 ++++ .../xcshareddata/IDEWorkspaceChecks.plist | 8 ++++++++ 3 files changed, 12 insertions(+), 5 deletions(-) create mode 100644 Miller-Rabin Primality Test/MRPrimality.playground/playground.xcworkspace/contents.xcworkspacedata create mode 100644 Miller-Rabin Primality Test/MRPrimality.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist diff --git a/Miller-Rabin Primality Test/MRPrimality.playground/Contents.swift b/Miller-Rabin Primality Test/MRPrimality.playground/Contents.swift index d8fd7fad8..98032bd59 100644 --- a/Miller-Rabin Primality Test/MRPrimality.playground/Contents.swift +++ b/Miller-Rabin Primality Test/MRPrimality.playground/Contents.swift @@ -1,10 +1,5 @@ //: Playground - noun: a place where people can play -// last checked with Xcode 9.0b4 -#if swift(>=4.0) -print("Hello, Swift 4!") -#endif - // Real primes mrPrimalityTest(5) mrPrimalityTest(439) diff --git a/Miller-Rabin Primality Test/MRPrimality.playground/playground.xcworkspace/contents.xcworkspacedata b/Miller-Rabin Primality Test/MRPrimality.playground/playground.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..94b2795e2 --- /dev/null +++ b/Miller-Rabin Primality Test/MRPrimality.playground/playground.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,4 @@ + + + diff --git a/Miller-Rabin Primality Test/MRPrimality.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Miller-Rabin Primality Test/MRPrimality.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/Miller-Rabin Primality Test/MRPrimality.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + From 027dc783bb15853c40f15bfd11daa9dcb7771120 Mon Sep 17 00:00:00 2001 From: Pragati <44121852+pragatiahuja@users.noreply.github.com> Date: Mon, 15 Oct 2018 23:50:03 +0530 Subject: [PATCH 101/271] final README Add recursive implementation for reversing a singly linked list. --- Linked List/README.markdown | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/Linked List/README.markdown b/Linked List/README.markdown index 0c8431157..0998349fc 100644 --- a/Linked List/README.markdown +++ b/Linked List/README.markdown @@ -471,6 +471,7 @@ This will print the list like so: How about reversing a list, so that the head becomes the tail and vice versa? There is a very fast algorithm for that: +Iterative Approach: ```swift public func reverse() { var node = head @@ -482,6 +483,18 @@ How about reversing a list, so that the head becomes the tail and vice versa? Th } } ``` +Recursive Approach: +```swift + public func reverse(node: head) { + if (!head || !(head.next)) { + return head + } + let temp = reverse(head.next) + head.next.next = head; + head.next = NULL; + return temp; + } +``` This loops through the entire list and simply swaps the `next` and `previous` pointers of each node. It also moves the `head` pointer to the very last element. (If you had a tail pointer you'd also need to update it.) You end up with something like this: From 75783274fd291f6f9e6e801734c1eefa3b77eb38 Mon Sep 17 00:00:00 2001 From: Julio Brazil Date: Tue, 16 Oct 2018 11:35:51 -0300 Subject: [PATCH 102/271] replaced repetitive implementation with call --- .../Sources/SelectionSort.swift | 20 +------------------ 1 file changed, 1 insertion(+), 19 deletions(-) diff --git a/Selection Sort/SelectionSort.playground/Sources/SelectionSort.swift b/Selection Sort/SelectionSort.playground/Sources/SelectionSort.swift index 3a27ef9dd..e7c66481d 100644 --- a/Selection Sort/SelectionSort.playground/Sources/SelectionSort.swift +++ b/Selection Sort/SelectionSort.playground/Sources/SelectionSort.swift @@ -3,25 +3,7 @@ /// - Parameter array: array of elements that conform to the Comparable protocol /// - Returns: an array in ascending order public func selectionSort(_ array: [T]) -> [T] { - guard array.count > 1 else { return array } - - var a = array - for x in 0 ..< a.count - 1 { - - // Find the lowest value in the rest of the array. - var lowest = x - for y in x + 1 ..< a.count { - if a[y] < a[lowest] { - lowest = y - } - } - - // Swap the lowest value with the current array index. - if x != lowest { - a.swapAt(x, lowest) - } - } - return a + return insertionSort(array, <) } /// Performs the Selection sort algorithm on a array using the provided comparisson method From 35ca62c82b39506203e551c8d05938113aec3e2f Mon Sep 17 00:00:00 2001 From: TaeJoongYoon Date: Wed, 17 Oct 2018 04:05:46 +0900 Subject: [PATCH 103/271] Add CounterClockWise(CCW) --- .../Contents.swift | 76 +++++++++++ .../contents.xcplayground | 4 + .../contents.xcworkspacedata | 7 ++ .../xcshareddata/IDEWorkspaceChecks.plist | 8 ++ CounterClockWise/CounterClockWise.swift | 50 ++++++++ CounterClockWise/Images/Pentagon_img.png | Bin 0 -> 20639 bytes CounterClockWise/Images/Quadrilateral_img.jpg | Bin 0 -> 9081 bytes CounterClockWise/Images/Shoelace.png | Bin 0 -> 77353 bytes CounterClockWise/Images/Triangle_img.jpg | Bin 0 -> 10346 bytes CounterClockWise/Images/pentagon.png | Bin 0 -> 25285 bytes CounterClockWise/Images/quadrilateral.png | Bin 0 -> 22372 bytes CounterClockWise/Images/triangle.png | Bin 0 -> 19654 bytes CounterClockWise/README.md | 118 ++++++++++++++++++ README.markdown | 1 + 14 files changed, 264 insertions(+) create mode 100644 CounterClockWise/CounterClockWise.playground/Contents.swift create mode 100644 CounterClockWise/CounterClockWise.playground/contents.xcplayground create mode 100644 CounterClockWise/CounterClockWise.playground/playground.xcworkspace/contents.xcworkspacedata create mode 100644 CounterClockWise/CounterClockWise.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist create mode 100644 CounterClockWise/CounterClockWise.swift create mode 100644 CounterClockWise/Images/Pentagon_img.png create mode 100644 CounterClockWise/Images/Quadrilateral_img.jpg create mode 100644 CounterClockWise/Images/Shoelace.png create mode 100644 CounterClockWise/Images/Triangle_img.jpg create mode 100644 CounterClockWise/Images/pentagon.png create mode 100644 CounterClockWise/Images/quadrilateral.png create mode 100644 CounterClockWise/Images/triangle.png create mode 100644 CounterClockWise/README.md diff --git a/CounterClockWise/CounterClockWise.playground/Contents.swift b/CounterClockWise/CounterClockWise.playground/Contents.swift new file mode 100644 index 000000000..ffa91ecbb --- /dev/null +++ b/CounterClockWise/CounterClockWise.playground/Contents.swift @@ -0,0 +1,76 @@ +/* + CounterClockWise(CCW) Algorithm + The user cross-multiplies corresponding coordinates to find the area encompassing the polygon, + and subtracts it from the surrounding polygon to find the area of the polygon within. + This code is based on the "Shoelace formula" by Carl Friedrich Gauss + https://en.wikipedia.org/wiki/Shoelace_formula + */ + +import Foundation + +// MARK : Point struct for defining 2-D coordinate(x,y) +public struct Point{ + // Coordinate(x,y) + var x: Int + var y: Int + + public init(x: Int ,y: Int){ + self.x = x + self.y = y + } +} + +// MARK : Function that determine the area of a simple polygon whose vertices are described +// by their Cartesian coordinates in the plane. +func ccw(points: [Point]) -> Int{ + let polygon = points.count + var orientation = 0 + + // Take the first x-coordinate and multiply it by the second y-value, + // then take the second x-coordinate and multiply it by the third y-value, + // and repeat as many times until it is done for all wanted points. + for i in 0.. 0 : CounterClockWise + } +} + +// A few simple tests + + +// Triangle +var p1 = Point(x: 5, y: 8) +var p2 = Point(x: 9, y: 1) +var p3 = Point(x: 3, y: 6) + +print(ccw(points: [p1,p2,p3])) // -1 means ClockWise + +// Quadrilateral +var p4 = Point(x: 5, y: 8) +var p5 = Point(x: 2, y: 3) +var p6 = Point(x: 6, y: 1) +var p7 = Point(x: 9, y: 3) + +print(ccw(points: [p4,p5,p6,p7])) // 1 means CounterClockWise + +// Pentagon +var p8 = Point(x: 5, y: 11) +var p9 = Point(x: 3, y: 4) +var p10 = Point(x: 5, y: 6) +var p11 = Point(x: 9, y: 5) +var p12 = Point(x: 12, y: 8) + +print(ccw(points: [p8,p9,p10,p11,p12])) // 1 means CounterClockWise diff --git a/CounterClockWise/CounterClockWise.playground/contents.xcplayground b/CounterClockWise/CounterClockWise.playground/contents.xcplayground new file mode 100644 index 000000000..9f5f2f40c --- /dev/null +++ b/CounterClockWise/CounterClockWise.playground/contents.xcplayground @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/CounterClockWise/CounterClockWise.playground/playground.xcworkspace/contents.xcworkspacedata b/CounterClockWise/CounterClockWise.playground/playground.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..919434a62 --- /dev/null +++ b/CounterClockWise/CounterClockWise.playground/playground.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/CounterClockWise/CounterClockWise.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/CounterClockWise/CounterClockWise.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/CounterClockWise/CounterClockWise.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/CounterClockWise/CounterClockWise.swift b/CounterClockWise/CounterClockWise.swift new file mode 100644 index 000000000..07c422ea5 --- /dev/null +++ b/CounterClockWise/CounterClockWise.swift @@ -0,0 +1,50 @@ +/* + CounterClockWise(CCW) Algorithm + The user cross-multiplies corresponding coordinates to find the area encompassing the polygon, + and subtracts it from the surrounding polygon to find the area of the polygon within. + This code is based on the "Shoelace formula" by Carl Friedrich Gauss + https://en.wikipedia.org/wiki/Shoelace_formula + */ + + +import Foundation + +// MARK : Point struct for defining 2-D coordinate(x,y) +public struct Point{ + // Coordinate(x,y) + var x: Int + var y: Int + + public init(x: Int ,y: Int){ + self.x = x + self.y = y + } +} + +// MARK : Function that determine the area of a simple polygon whose vertices are described +// by their Cartesian coordinates in the plane. +func ccw(points: [Point]) -> Int{ + let polygon = points.count + var orientation = 0 + + // Take the first x-coordinate and multiply it by the second y-value, + // then take the second x-coordinate and multiply it by the third y-value, + // and repeat as many times until it is done for all wanted points. + for i in 0.. 0 : CounterClockWise + } +} diff --git a/CounterClockWise/Images/Pentagon_img.png b/CounterClockWise/Images/Pentagon_img.png new file mode 100644 index 0000000000000000000000000000000000000000..44d8583036420e6a63fd0c339f65845632ebf28c GIT binary patch literal 20639 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 KKa5kxeEKh=GplU? literal 0 HcmV?d00001 diff --git a/CounterClockWise/Images/Shoelace.png b/CounterClockWise/Images/Shoelace.png new file mode 100644 index 0000000000000000000000000000000000000000..2691ec1294a52ec20b19d331aa40619fad6e9cf4 GIT binary patch literal 77353 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 IkhKc`ALKjdm;e9( literal 0 HcmV?d00001 diff --git a/CounterClockWise/Images/Triangle_img.jpg b/CounterClockWise/Images/Triangle_img.jpg new file mode 100644 index 0000000000000000000000000000000000000000..8a010ca1507f1fcf404a7d9b9e98bc5d08acfdc8 GIT binary patch literal 10346 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 literal 0 HcmV?d00001 diff --git a/CounterClockWise/Images/pentagon.png b/CounterClockWise/Images/pentagon.png new file mode 100644 index 0000000000000000000000000000000000000000..063c77900648abd632cdb26b9e12a01efdd1892d GIT binary patch literal 25285 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 literal 0 HcmV?d00001 diff --git a/CounterClockWise/Images/quadrilateral.png b/CounterClockWise/Images/quadrilateral.png new file mode 100644 index 0000000000000000000000000000000000000000..139d097788289c7115ae827f2c8a6ca3f3312f85 GIT binary patch literal 22372 zcmagF1yr2PvMvn49Rk5!g1fuBLlWHG9R_#z;O-jS-Ge&>5AF_w>p$#!?z!iDd$0A+ zddK?huI{d?uIhfCnQ$cqNhEk&crY+9Bxxxz6)-SJD$r+3SZL6zPqTg)7#O0gg{Y{K zw5TYtlB1oeg|!J7m{fR@8q7D<5!`Go6=`#SSSh$pIF&+KxIA&xIGQC`Y2v(rR8+B3 zhDi7-9kHH}stBs{WB6fBRD>q++WXM9(u#^mC_EZF6`@7`i%#I1lj(Vi@7v?s&sHZh zu<5cb=_2=12C&DUpEN{_sjLh&c_MF6mB8VMg%AK&502El0s_!NI3900>)N5oN>wdX zt#90Kdg6-2i9m3nZIVfh;m1eR_fKHDeJP{xV8l-%owwtk%04TGED1qF1gVz~EL&>l z52RUYm(@wjYzlS2fU!gmC73|u{zbg45b@#Io#}$B%@89_2Fn!<;R<8ih9iy%0DSX# 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