├── .gitignore ├── algorithms ├── AI │ └── minimax │ │ ├── Resources │ │ ├── demo.gif │ │ └── image1.jpg │ │ ├── Sources │ │ ├── Minimax.playground │ │ │ ├── Sources │ │ │ │ ├── Model │ │ │ │ │ ├── Board │ │ │ │ │ │ ├── BoardPosition.swift │ │ │ │ │ │ ├── BoardStatus.swift │ │ │ │ │ │ └── Board.swift │ │ │ │ │ ├── Player │ │ │ │ │ │ ├── PlayerType.swift │ │ │ │ │ │ ├── PlayerSymbol.swift │ │ │ │ │ │ └── Player.swift │ │ │ │ │ ├── Minimax │ │ │ │ │ │ ├── GameStateValue.swift │ │ │ │ │ │ └── Minimax.swift │ │ │ │ │ └── GameModel │ │ │ │ │ │ ├── DifficultLevel.swift │ │ │ │ │ │ └── GameModel.swift │ │ │ │ └── View │ │ │ │ │ └── BoardView.swift │ │ │ ├── playground.xcworkspace │ │ │ │ ├── contents.xcworkspacedata │ │ │ │ └── xcshareddata │ │ │ │ │ └── WorkspaceSettings.xcsettings │ │ │ ├── contents.xcplayground │ │ │ └── Contents.swift │ │ └── Tests │ │ │ ├── Tests.xcodeproj │ │ │ ├── project.xcworkspace │ │ │ │ ├── contents.xcworkspacedata │ │ │ │ └── xcshareddata │ │ │ │ │ ├── IDEWorkspaceChecks.plist │ │ │ │ │ └── WorkspaceSettings.xcsettings │ │ │ └── project.pbxproj │ │ │ └── Tests │ │ │ ├── PlayerTests.swift │ │ │ ├── Info.plist │ │ │ ├── MinimaxTests.swift │ │ │ └── BoardTests.swift │ │ └── README.md ├── conversion │ ├── decimal-to-binary.swift │ └── binary-to-decimal.swift ├── palindrome │ ├── palindrome_reversed.swift │ ├── palindrome_indices.swift │ └── palindrome_recursion.swift └── parsing │ └── shunting_yard │ └── shunting_yard.swift ├── README.md ├── recursion └── fibonacci.swift ├── Search ├── LinearSearch.swift └── BinarySearch.swift ├── data_structures ├── queue │ └── queue.swift ├── Stack │ └── stack.swift ├── union_find │ └── union_find.swift ├── heap │ └── heap.swift ├── Linked List │ └── LinkedList.swift └── doubly_linked_list │ └── DoublyLinkedList.swift ├── sorts ├── BubbleSort.swift ├── InsertionSort.swift ├── SelectionSort.swift ├── CocktailSort.swift ├── PancakeSort.swift ├── MergeSort.swift └── QuickSort.swift ├── trees └── tree.swift ├── graph ├── DFS │ └── DFS.swift ├── spanning_tree │ ├── kruskal.swift │ └── dijkstra.swift ├── BFS │ └── BFS.swift └── Graph.swift ├── .github └── workflows │ ├── .stale.yml │ └── directory_workflow.yml └── DIRECTORY.md /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | -------------------------------------------------------------------------------- /algorithms/AI/minimax/Resources/demo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheAlgorithms/Swift/HEAD/algorithms/AI/minimax/Resources/demo.gif -------------------------------------------------------------------------------- /algorithms/AI/minimax/Resources/image1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheAlgorithms/Swift/HEAD/algorithms/AI/minimax/Resources/image1.jpg -------------------------------------------------------------------------------- /algorithms/AI/minimax/Sources/Minimax.playground/Sources/Model/Board/BoardPosition.swift: -------------------------------------------------------------------------------- 1 | public typealias Position = (row: Int, column: Int) 2 | -------------------------------------------------------------------------------- /algorithms/AI/minimax/Sources/Minimax.playground/Sources/Model/Player/PlayerType.swift: -------------------------------------------------------------------------------- 1 | public enum PlayerType { 2 | 3 | case computer 4 | 5 | case human 6 | } 7 | -------------------------------------------------------------------------------- /algorithms/AI/minimax/Sources/Minimax.playground/Sources/Model/Board/BoardStatus.swift: -------------------------------------------------------------------------------- 1 | public enum BoardStatus { 2 | 3 | case continues 4 | 5 | case win 6 | 7 | case draw 8 | } 9 | -------------------------------------------------------------------------------- /algorithms/AI/minimax/Sources/Minimax.playground/Sources/Model/Minimax/GameStateValue.swift: -------------------------------------------------------------------------------- 1 | public enum GameStateValue: Int { 2 | 3 | case min = -1 4 | 5 | case null = 0 6 | 7 | case max = 1 8 | } 9 | -------------------------------------------------------------------------------- /algorithms/AI/minimax/Sources/Minimax.playground/Sources/Model/GameModel/DifficultLevel.swift: -------------------------------------------------------------------------------- 1 | public enum DifficultLevel: Int { 2 | 3 | case easy = 2 4 | 5 | case medium = 3 6 | 7 | case hard = 5 8 | } 9 | -------------------------------------------------------------------------------- /algorithms/AI/minimax/Sources/Minimax.playground/Sources/Model/Player/PlayerSymbol.swift: -------------------------------------------------------------------------------- 1 | public enum PlayerSymbol: String { 2 | 3 | case empty = "" 4 | 5 | case circle = "⭕️" 6 | 7 | case cross = "❌" 8 | } 9 | -------------------------------------------------------------------------------- /algorithms/AI/minimax/Sources/Minimax.playground/playground.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /algorithms/AI/minimax/Sources/Tests/Tests.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /algorithms/AI/minimax/Sources/Minimax.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /algorithms/AI/minimax/Sources/Minimax.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | import PlaygroundSupport 3 | 4 | let boardSize = CGSize(width: 500, height: 550) 5 | let boardView = BoardView(frame: CGRect(origin: .zero, size: boardSize)) 6 | 7 | PlaygroundPage.current.needsIndefiniteExecution = true 8 | PlaygroundPage.current.liveView = boardView 9 | -------------------------------------------------------------------------------- /algorithms/AI/minimax/Sources/Tests/Tests.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /algorithms/AI/minimax/Sources/Minimax.playground/playground.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEWorkspaceSharedSettings_AutocreateContextsIfNeeded 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /algorithms/AI/minimax/Sources/Tests/Tests.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEWorkspaceSharedSettings_AutocreateContextsIfNeeded 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /algorithms/AI/minimax/Sources/Minimax.playground/Sources/Model/Player/Player.swift: -------------------------------------------------------------------------------- 1 | public struct Player { 2 | // MARK: -- Public variable's 3 | public var type: PlayerType 4 | 5 | public var symbol: PlayerSymbol 6 | 7 | // MARK: -- Public function's 8 | public init(type: PlayerType, symbol: PlayerSymbol) { 9 | self.type = type 10 | self.symbol = symbol 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # The Algorithms - Swift 2 | 3 | ### All algorithms implemented in Swift (for education) 4 | 5 | These implementations are for learning purposes. They may be less efficient than the implementations in the Swift standard library. 6 | 7 | ## Community Channel 8 | 9 | We're on [Gitter](https://gitter.im/TheAlgorithms)! Please join us. 10 | 11 | ## List of Algorithms 12 | 13 | See our [directory](DIRECTORY.md). 14 | -------------------------------------------------------------------------------- /algorithms/conversion/decimal-to-binary.swift: -------------------------------------------------------------------------------- 1 | /// This function accepts a non-negative number and returns its binary form as String. 2 | public func convertDecimalToBinary(decimal: Int) -> String { 3 | var binary = "" 4 | var decimal = decimal 5 | 6 | while decimal != 0 { 7 | binary.insert(decimal % 2 == 0 ? "0" : "1", at: binary.startIndex) 8 | decimal /= 2 9 | } 10 | 11 | return binary 12 | } -------------------------------------------------------------------------------- /recursion/fibonacci.swift: -------------------------------------------------------------------------------- 1 | // The Fibonacci numbers, commonly denoted F(n) form a sequence, 2 | // called the Fibonacci sequence, such that # each number is the sum 3 | // of the two preceding ones, starting from 0 and 1. That is, 4 | // 5 | // F(0) = 0, F(1) = 1 6 | // F(n) = F(n - 1) + F(n - 2), for n > 1 7 | // 8 | // Given n, calculate F(n). 9 | // 10 | // @leticiafaleia 11 | func fibonacci(_ number: Int) -> Int { 12 | guard number > 1 else { return number } 13 | return fibonacci(number - 1) + fibonacci(number - 2) 14 | } 15 | 16 | fibonacci(5) 17 | -------------------------------------------------------------------------------- /Search/LinearSearch.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | func linearSearch(_ array: [T], _ object: T) -> Int? { 4 | for (index, obj) in array.enumerated() where obj == object { 5 | return index 6 | } 7 | return nil 8 | } 9 | 10 | // The code below can be used for testing 11 | 12 | // var numbers = [10, 119, 13, 24, 53, 17, 31, 7, 19, 627, 47, 163, 37, 611, 29, 43, 51, 41, 32] 13 | // if let searchIndex = linearSearch(numbers,31) { 14 | // print("Element found on index: \(searchIndex)") 15 | // } 16 | // else { 17 | // print("Element not found") 18 | // } 19 | -------------------------------------------------------------------------------- /algorithms/palindrome/palindrome_reversed.swift: -------------------------------------------------------------------------------- 1 | // A palindrome is a string that reads the same forwards and backwards. 2 | // 3 | // Examples: "level", "radar", "madam", "A man, a plan, a canal: Panama". 4 | 5 | extension String { 6 | 7 | /// Using the `reverse()` method to reverse the string and comparing it with the original. Only include letters and numbers. 8 | /// - Complexity: O(n), with allocating O(n) space. 9 | func isPalindrome() -> Bool { 10 | let input = lowercased().filter { $0.isLetter || $0.isNumber } 11 | return input == String(input.reversed()) 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /data_structures/queue/queue.swift: -------------------------------------------------------------------------------- 1 | // Create simple queue 2 | // Tejas Nanaware 3 | 4 | struct Queue { 5 | private var elements: [T] = [] 6 | 7 | mutating func push(_ value: T) { 8 | elements.append(value) 9 | } 10 | 11 | mutating func pop() -> T? { 12 | guard !elements.isEmpty else { 13 | return nil 14 | } 15 | return elements.removeFirst() 16 | } 17 | } 18 | 19 | var queue = Queue() 20 | 21 | queue.push("One") 22 | queue.push("Two") 23 | queue.push("Three") 24 | 25 | print(queue.pop()) 26 | print(queue) 27 | print(queue.pop()) 28 | print(queue) 29 | print(queue.pop()) 30 | print(queue) 31 | -------------------------------------------------------------------------------- /algorithms/AI/minimax/Sources/Tests/Tests/PlayerTests.swift: -------------------------------------------------------------------------------- 1 | import XCTest 2 | 3 | class PlayerTests: XCTestCase { 4 | 5 | private var sut: Player! 6 | 7 | private var playerType: PlayerType = .human 8 | 9 | private var playerSymbol: PlayerSymbol = .circle 10 | 11 | override func setUp() { 12 | super.setUp() 13 | sut = Player(type: playerType, symbol: playerSymbol) 14 | } 15 | 16 | override func tearDown() { 17 | sut = nil 18 | super.tearDown() 19 | } 20 | 21 | func testInit() { 22 | XCTAssertEqual(sut.type, playerType) 23 | XCTAssertEqual(sut.symbol, playerSymbol) 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /algorithms/conversion/binary-to-decimal.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | /// This function accepts a binary number as String and converts it to decimal as Int. 4 | /// If it's not valid binary number (a.k.a not made only from digits), it returns nil. 5 | public func convertBinaryToDecimal(binary: String) -> Int? { 6 | if let _ = Int(binary) { 7 | var decimal = 0 8 | 9 | let digits = binary.map { Int(String($0))! }.reversed() 10 | print(digits) 11 | var power = 1 12 | 13 | for digit in digits { 14 | decimal += digit * power 15 | 16 | power *= 2 17 | } 18 | 19 | return decimal 20 | } 21 | 22 | return nil 23 | } -------------------------------------------------------------------------------- /algorithms/AI/minimax/Sources/Tests/Tests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | $(PRODUCT_BUNDLE_PACKAGE_TYPE) 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /sorts/BubbleSort.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | extension Array where Element: Comparable { 4 | 5 | func bubbleSort(by areInIncreasingOrder: ((Element, Element) -> Bool) = (<)) -> [Element] { 6 | var data = self 7 | 8 | for i in 0..<(data.count-1) { 9 | for j in 0..<(data.count-i-1) where areInIncreasingOrder(data[j+1], data[j]) { 10 | data.swapAt(j, j + 1) 11 | } 12 | } 13 | 14 | return data 15 | } 16 | } 17 | 18 | func swap(left: inout T, right: inout T) { 19 | print("Swapping \(left) and \(right)") 20 | let temp = right 21 | right = left 22 | left = temp 23 | } 24 | 25 | // The code below can be used for testing 26 | 27 | // let numberList : Array = [8, 2, 10, 9, 7, 5] 28 | // let results: Array = numberList.bubbleSort() 29 | // print(results) 30 | -------------------------------------------------------------------------------- /Search/BinarySearch.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public func binarySearch(_ a: [T], key: T) -> Int? { 4 | var lowerBound = 0 5 | var upperBound = a.count 6 | while lowerBound < upperBound { 7 | let midIndex = lowerBound + (upperBound - lowerBound) / 2 8 | if a[midIndex] == key { 9 | return midIndex 10 | } else if a[midIndex] < key { 11 | lowerBound = midIndex + 1 12 | } else { 13 | upperBound = midIndex 14 | } 15 | } 16 | return nil 17 | } 18 | // The code below can be used for testing 19 | 20 | // var numbers = [7, 10, 13, 17, 19, 24, 29, 31, 32, 37, 41, 43, 47, 51, 53, 119, 163, 611, 627] 21 | // if let searchIndex = binarySearch(numbers, key: 10) { 22 | // print("Element found on index: \(searchIndex)") 23 | // } 24 | // else { 25 | // print("Element not found") 26 | // } 27 | 28 | -------------------------------------------------------------------------------- /data_structures/Stack/stack.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public struct Stack { 4 | private var elements = [T]() 5 | 6 | public mutating func push(_ element: T) { 7 | elements.append(element) 8 | } 9 | 10 | public mutating func pop() -> T? { 11 | return elements.popLast() 12 | } 13 | 14 | public var isEmpty: Bool { 15 | return elements.isEmpty 16 | } 17 | 18 | public var count: Int { 19 | return elements.count 20 | } 21 | 22 | public var peek: T? { 23 | return elements.last 24 | } 25 | } 26 | 27 | // The code below can be used for testing 28 | 29 | var stack = Stack() 30 | 31 | stack.push(10) 32 | stack.push(20) 33 | stack.push(30) 34 | 35 | print(stack.count) 36 | print(stack.peek) 37 | print(stack.isEmpty) 38 | 39 | print(stack.pop()) 40 | print(stack.pop()) 41 | print(stack.pop()) 42 | print(stack.isEmpty) 43 | print(stack.count) 44 | -------------------------------------------------------------------------------- /sorts/InsertionSort.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | func insertionSort(_ array: [T], by comparison: (T, T) -> Bool) -> [T] { 4 | guard array.count > 1 else { return array } 5 | 6 | var sortedArray = array 7 | 8 | for index in 1.. 0, comparison(temp, sortedArray[currentIndex - 1]) { 13 | sortedArray[currentIndex] = sortedArray[currentIndex - 1] 14 | currentIndex -= 1 15 | } 16 | sortedArray[currentIndex] = temp 17 | } 18 | 19 | return sortedArray 20 | } 21 | 22 | // The code below can be used for testing 23 | 24 | /* 25 | let numbers = [10, 1, 3, 8, 4, 2] 26 | 27 | print(insertionSort(numbers, by: >)) 28 | print(insertionSort(numbers, by: <)) 29 | 30 | let names = ["Jack", "Paul", "Olivia", "Emma", "Michael"] 31 | 32 | print(insertionSort(names, by: >)) 33 | print(insertionSort(names, by: <)) 34 | */ 35 | -------------------------------------------------------------------------------- /sorts/SelectionSort.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | extension Array where Element: Comparable { 4 | func selectionSort() -> Array { 5 | 6 | guard self.count > 1 else { 7 | return self 8 | } 9 | 10 | var output: Array = self 11 | 12 | for primaryindex in 0.. output[secondaryindex] { 20 | minimum = secondaryindex 21 | } 22 | secondaryindex += 1 23 | } 24 | 25 | if primaryindex != minimum { 26 | output.swapAt(primaryindex, minimum) 27 | } 28 | } 29 | 30 | return output 31 | } 32 | } 33 | 34 | // The code below can be used for testing 35 | 36 | // let numberList : Array = [15, 2, 23, 11, 3, 9] 37 | // let results: Array = numberList.selectionSort() 38 | // print(results) 39 | -------------------------------------------------------------------------------- /algorithms/palindrome/palindrome_indices.swift: -------------------------------------------------------------------------------- 1 | // A palindrome is a string that reads the same forwards and backwards. 2 | // 3 | // Examples: "level", "radar", "madam", "A man, a plan, a canal: Panama". 4 | 5 | extension String { 6 | 7 | /// Iteratively comparing characters from the beginning and end of the string. Only include letters and numbers. 8 | /// - Complexity: O(n), without allocating new space. 9 | func isPalindrome() -> Bool { 10 | var leftIndex = startIndex 11 | var rightIndex = index(before: endIndex) 12 | 13 | while leftIndex < rightIndex { 14 | guard self[leftIndex].isLetter || self[leftIndex].isNumber else { 15 | leftIndex = index(after: leftIndex) 16 | continue 17 | } 18 | guard self[rightIndex].isLetter || self[rightIndex].isNumber else { 19 | rightIndex = index(before: rightIndex) 20 | continue 21 | } 22 | guard self[leftIndex].lowercased() == self[rightIndex].lowercased() else { 23 | return false 24 | } 25 | 26 | leftIndex = index(after: leftIndex) 27 | rightIndex = index(before: rightIndex) 28 | } 29 | 30 | return true 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /sorts/CocktailSort.swift: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | Cocktail Sort (or Cocktail shaker sort) is a variation of Bubble sort. 4 | The Bubble sort algorithm always traverses elements from left and moves the largest element 5 | to its correct position in first iteration and second largest in second iteration and so on. 6 | Cocktail Sort traverses through a given array in both directions alternatively. 7 | */ 8 | 9 | import Foundation 10 | 11 | func cocktailSort(_ a: [T]) -> [T] { 12 | var list = a 13 | var swapped = true 14 | var start = 0 15 | var end = list.count - 1 16 | 17 | while (swapped) { 18 | swapped = false 19 | 20 | for i in start.. list[i + 1]) { 22 | list.swapAt(i, i+1) 23 | swapped = true 24 | } 25 | } 26 | 27 | if (!swapped) { 28 | break 29 | } 30 | swapped = false 31 | end -= 1 32 | 33 | for index in stride(from: end-1, through: start, by: -1) { 34 | if (list[index] > list[index + 1]) { 35 | list.swapAt(index, index+1) 36 | swapped = true 37 | } 38 | } 39 | start += 1 40 | } 41 | 42 | return list 43 | } 44 | 45 | // The code below can be used for testing 46 | 47 | //var numbers = [2, -4, 4, 6, 1, 12, 9, 0] 48 | //numbers = cocktailSort(numbers) 49 | //print(numbers) 50 | -------------------------------------------------------------------------------- /sorts/PancakeSort.swift: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | Pancake sorting is the mathematical problem of sorting a disordered stack 4 | of pancakes in order of size when a spatula can be inserted at any 5 | point in the stack and used to flip all pancakes above it. 6 | */ 7 | 8 | import Foundation 9 | 10 | func flip(array: [Int], key: Int) -> [Int] { 11 | var flippedArray = array 12 | var pos = key 13 | var start = 0 14 | var aux = 0 15 | 16 | while (start < pos) { 17 | aux = flippedArray[start] 18 | flippedArray[start] = flippedArray[pos] 19 | flippedArray[pos] = aux 20 | 21 | start += 1 22 | pos -= 1 23 | } 24 | 25 | return flippedArray 26 | } 27 | 28 | func pancakeSort(_ array: [Int]) -> [Int] { 29 | var list = array 30 | var currentSize = list.count 31 | for _ in (1 ..< currentSize).reversed() { 32 | 33 | let listToSearch = list[0...currentSize-1] 34 | let max = listToSearch.max() ?? 0 35 | let indexOfMax = listToSearch.firstIndex(of: max) ?? 0 36 | 37 | if indexOfMax != currentSize - 1 { 38 | list = flip(array: list, key: indexOfMax) 39 | list = flip(array: list, key: currentSize - 1) 40 | } 41 | 42 | currentSize -= 1 43 | } 44 | 45 | return list 46 | } 47 | 48 | // The code below can be used for testing 49 | //var numbers = [2, 4, 6, 12, 3, -2, 9, 14, 22, 0, 18] 50 | //numbers = pancakeSort(numbers) 51 | //print(numbers) 52 | -------------------------------------------------------------------------------- /algorithms/palindrome/palindrome_recursion.swift: -------------------------------------------------------------------------------- 1 | // A palindrome is a string that reads the same forwards and backwards. 2 | // 3 | // Examples: "level", "radar", "madam", "A man, a plan, a canal: Panama". 4 | 5 | extension String { 6 | 7 | /// Recursively comparing characters from the beginning and end of the string. Only include letters and numbers. 8 | /// - Complexity: O(n), without allocating new space. 9 | func isPalindrome() -> Bool { 10 | isPalindromeRecursion( 11 | leftIndex: startIndex, 12 | rightIndex: index(before: endIndex) 13 | ) 14 | } 15 | 16 | private func isPalindromeRecursion( 17 | leftIndex: String.Index, 18 | rightIndex: String.Index 19 | ) -> Bool { 20 | guard leftIndex < rightIndex else { 21 | return true 22 | } 23 | guard self[leftIndex].isLetter || self[leftIndex].isNumber else { 24 | return isPalindromeRecursion( 25 | leftIndex: index(after: leftIndex), 26 | rightIndex: rightIndex 27 | ) 28 | } 29 | guard self[rightIndex].isLetter || self[rightIndex].isNumber else { 30 | return isPalindromeRecursion( 31 | leftIndex: leftIndex, 32 | rightIndex: index(before: rightIndex) 33 | ) 34 | } 35 | guard self[leftIndex].lowercased() == self[rightIndex].lowercased() else { 36 | return false 37 | } 38 | 39 | return isPalindromeRecursion( 40 | leftIndex: index(after: leftIndex), 41 | rightIndex: index(before: rightIndex) 42 | ) 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /trees/tree.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public class TreeNode { 4 | public var value: T 5 | 6 | public weak var parent: TreeNode? 7 | public var children = [TreeNode]() 8 | 9 | public init(value: T) { 10 | self.value = value 11 | } 12 | 13 | public func addChild(_ node: TreeNode) { 14 | children.append(node) 15 | node.parent = self 16 | } 17 | } 18 | 19 | /* Checks the node's value property, if there is no match, check the child nodes. 20 | Repeat the same process recursively */ 21 | extension TreeNode where T: Equatable { 22 | func search(_ value: T) -> TreeNode? { 23 | if value == self.value { 24 | return self 25 | } 26 | for child in children { 27 | if let found = child.search(value) { 28 | return found 29 | } 30 | } 31 | return nil 32 | } 33 | } 34 | 35 | // The code below can be used for testing 36 | let tree = TreeNode(value: "animals") 37 | 38 | let reptilesNode = TreeNode(value: "reptiles") 39 | let mammalsNode = TreeNode(value: "mammals") 40 | 41 | let lizardsNode = TreeNode(value: "lizards") 42 | let snakesNode = TreeNode(value: "snakes") 43 | 44 | let dogsNode = TreeNode(value: "dogs") 45 | let humansNode = TreeNode(value: "humans") 46 | 47 | tree.addChild(reptilesNode) 48 | tree.addChild(mammalsNode) 49 | 50 | reptilesNode.addChild(lizardsNode) 51 | reptilesNode.addChild(snakesNode) 52 | 53 | mammalsNode.addChild(dogsNode) 54 | mammalsNode.addChild(humansNode) 55 | 56 | print(tree.search("humans")?.value) 57 | print(tree.search("lizards")?.value) 58 | print(tree.search("dragons")?.value) 59 | -------------------------------------------------------------------------------- /graph/DFS/DFS.swift: -------------------------------------------------------------------------------- 1 | // MARK: - Basic requirement 2 | struct Edge { 3 | let from: Int 4 | let to: Int 5 | } 6 | 7 | public class Node { 8 | var val: Int 9 | var neighbors: [Int] 10 | public init(_ val: Int) { 11 | self.val = val 12 | self.neighbors = [] 13 | } 14 | } 15 | 16 | // MARK: - DFS Recursion 17 | func dfs(vertex: Int, visited: inout [Bool], graph: [Int: Node]) { 18 | if visited[vertex] == true { 19 | return 20 | } 21 | visited[vertex] = true 22 | print("\(vertex) ") 23 | guard let neighbors = graph[vertex] else { return } 24 | for neighbor in neighbors.neighbors { 25 | dfs(vertex: neighbor, visited: &visited, graph: graph) 26 | } 27 | } 28 | 29 | func testDFS(edges: [Edge]) { 30 | var graph = [Int: Node]() 31 | for edge in edges { 32 | graph[edge.from] = Node(edge.from) 33 | graph[edge.to] = Node(edge.to) 34 | } 35 | for edge in edges { 36 | graph[edge.from]?.neighbors.append(edge.to) 37 | graph[edge.to]?.neighbors.append(edge.from) 38 | } 39 | var visited: [Bool] = Array(repeating: false, count: graph.count + 1) 40 | for node in 1...graph.count { 41 | if visited[node] == false { 42 | dfs(vertex: node, visited: &visited, graph: graph) 43 | } 44 | } 45 | } 46 | 47 | 48 | // MARK: - setup 49 | func setup() { 50 | let edges = [ 51 | Edge(from: 1, to: 2), 52 | Edge(from: 1, to: 4), 53 | Edge(from: 2, to: 3), 54 | Edge(from: 2, to: 4), 55 | Edge(from: 2, to: 5), 56 | Edge(from: 3, to: 5), 57 | Edge(from: 4, to: 5), 58 | Edge(from: 4, to: 6), 59 | Edge(from: 5, to: 6), 60 | Edge(from: 5, to: 6), 61 | Edge(from: 6, to: 7), 62 | ] 63 | testDFS(edges: edges) 64 | } 65 | -------------------------------------------------------------------------------- /data_structures/union_find/union_find.swift: -------------------------------------------------------------------------------- 1 | class UnionFindNode { 2 | var rank = 0 3 | 4 | private var parent: UnionFindNode? = nil 5 | 6 | func findRoot() -> UnionFindNode { 7 | var x = self 8 | while let parent = x.parent { 9 | x.parent = parent.parent ?? parent 10 | x = parent 11 | } 12 | return x 13 | } 14 | 15 | @discardableResult 16 | static func union(_ x: UnionFindNode, _ y: UnionFindNode) -> UnionFindNode { 17 | var x = x.findRoot() 18 | var y = y.findRoot() 19 | 20 | guard x !== y else { return x } 21 | 22 | if x.rank < y.rank { 23 | swap(&x, &y) 24 | } 25 | 26 | y.parent = x 27 | if x.rank == y.rank { 28 | x.rank = y.rank + 1 29 | } 30 | 31 | return x 32 | } 33 | 34 | static func inSameSet(_ x: UnionFindNode, _ y: UnionFindNode) -> Bool { 35 | return x.findRoot() === y.findRoot() 36 | } 37 | } 38 | 39 | 40 | func testUnionFind() { 41 | let a = UnionFindNode() 42 | let b = UnionFindNode() 43 | let c = UnionFindNode() 44 | 45 | print("a, b", UnionFindNode.inSameSet(a, b)) 46 | print("b, c", UnionFindNode.inSameSet(b, c)) 47 | print("a, c", UnionFindNode.inSameSet(a, c)) 48 | 49 | print("Joining a, b") 50 | 51 | UnionFindNode.union(a, b) 52 | print("a, b", UnionFindNode.inSameSet(a, b)) 53 | print("b, c", UnionFindNode.inSameSet(b, c)) 54 | print("a, c", UnionFindNode.inSameSet(a, c)) 55 | 56 | print("Joining b, c") 57 | 58 | UnionFindNode.union(b, c) 59 | print("a, b", UnionFindNode.inSameSet(a, b)) 60 | print("b, c", UnionFindNode.inSameSet(b, c)) 61 | print("a, c", UnionFindNode.inSameSet(a, c)) 62 | 63 | 64 | print("New node d") 65 | let d = UnionFindNode() 66 | 67 | print("a, d", UnionFindNode.inSameSet(a, d)) 68 | 69 | print("Joining d, c") 70 | UnionFindNode.union(d, c) 71 | print("a, d", UnionFindNode.inSameSet(a, d)) 72 | 73 | } 74 | -------------------------------------------------------------------------------- /sorts/MergeSort.swift: -------------------------------------------------------------------------------- 1 | 2 | import Foundation 3 | 4 | extension Array where Element: Comparable { 5 | 6 | mutating func mergeSort(by comparison: (Element, Element) -> Bool) { 7 | guard self.count > 1 else { 8 | return 9 | } 10 | _mergeSort(from: 0, to: count - 1, by: comparison) 11 | } 12 | 13 | mutating private func _mergeSort( 14 | from left: Int, 15 | to right: Int, 16 | by comparison: (Element, Element) -> Bool 17 | ) { 18 | if left < right { 19 | let mid = left + (right - left) / 2 20 | _mergeSort(from: 0, to: mid, by: comparison) 21 | _mergeSort(from: mid + 1, to: right, by: comparison) 22 | _merge(from: left, mid: mid, to: right, by: comparison) 23 | } 24 | } 25 | 26 | mutating private func _merge( 27 | from left: Int, 28 | mid: Int, 29 | to right: Int, 30 | by comparison: (Element, Element) -> Bool 31 | ) { 32 | var copy = [Element](repeating: self[left], count: right - left + 1) 33 | var (leftStartIndex, rightStartIndex, currentIndex) = (left, mid + 1, 0) 34 | for _ in left ... right { 35 | if leftStartIndex > mid { 36 | copy[currentIndex] = self[rightStartIndex] 37 | rightStartIndex += 1 38 | } else if rightStartIndex > right { 39 | copy[currentIndex] = self[leftStartIndex] 40 | leftStartIndex += 1 41 | } else if comparison(self[leftStartIndex], self[rightStartIndex]) { 42 | copy[currentIndex] = self[leftStartIndex] 43 | leftStartIndex += 1 44 | } else { 45 | copy[currentIndex] = self[rightStartIndex] 46 | rightStartIndex += 1 47 | } 48 | currentIndex += 1 49 | } 50 | leftStartIndex = left 51 | for i in copy.indices { 52 | self[leftStartIndex] = copy[i] 53 | leftStartIndex += 1 54 | } 55 | } 56 | 57 | func mergeSorted(by comparison: (Element, Element) -> Bool) -> Array { 58 | var copy = self 59 | copy.mergeSort(by: comparison) 60 | return copy 61 | } 62 | 63 | } 64 | 65 | // The code below can be used for testing 66 | // var numberList = [15, 2, 23, 11, 3, 9] 67 | // debugPrint(numberList.mergeSorted(by: >)) 68 | // numberList.mergeSort(by: <) 69 | // debugPrint(numberList) 70 | -------------------------------------------------------------------------------- /graph/spanning_tree/kruskal.swift: -------------------------------------------------------------------------------- 1 | enum Kruskal { 2 | struct Vertex { 3 | let name: String 4 | let node = UnionFindNode() 5 | 6 | init(_ name: String) { 7 | self.name = name 8 | } 9 | } 10 | 11 | struct Edge { 12 | let from: Vertex 13 | let to: Vertex 14 | let weight: Int 15 | } 16 | 17 | typealias Graph = [Edge] 18 | 19 | 20 | static func kruskal(_ graph: Graph) -> Graph { 21 | var edges = Heap(graph) { $0.weight < $1.weight } 22 | 23 | var result: Graph = [] 24 | result.reserveCapacity(edges.count) 25 | 26 | while let edge = edges.extractMin() { 27 | guard !UnionFindNode.inSameSet(edge.from.node, edge.to.node) else { 28 | continue 29 | } 30 | UnionFindNode.union(edge.from.node, edge.to.node) 31 | result.append(edge) 32 | } 33 | 34 | return result 35 | } 36 | } 37 | 38 | extension Kruskal.Vertex: CustomStringConvertible { 39 | var description: String { name } 40 | } 41 | 42 | extension Kruskal.Edge: CustomStringConvertible { 43 | var description: String { "\(from) --(\(weight))-- \(to)" } 44 | } 45 | 46 | func testKruskal() { 47 | typealias Vertex = Kruskal.Vertex 48 | typealias Edge = Kruskal.Edge 49 | 50 | let A = Vertex("A") 51 | let B = Vertex("B") 52 | let C = Vertex("C") 53 | let D = Vertex("D") 54 | let E = Vertex("E") 55 | let F = Vertex("F") 56 | let G = Vertex("G") 57 | 58 | let graph = [ 59 | Edge(from: A, to: B, weight: 7), 60 | Edge(from: A, to: D, weight: 5), 61 | Edge(from: B, to: C, weight: 8), 62 | Edge(from: B, to: D, weight: 9), 63 | Edge(from: B, to: E, weight: 7), 64 | Edge(from: C, to: E, weight: 5), 65 | Edge(from: D, to: E, weight: 15), 66 | Edge(from: D, to: F, weight: 6), 67 | Edge(from: E, to: F, weight: 8), 68 | Edge(from: E, to: G, weight: 9), 69 | Edge(from: F, to: G, weight: 11), 70 | ] 71 | 72 | print(Kruskal.kruskal(graph).map { String(describing: $0) }.joined(separator: "\n") ) 73 | } 74 | -------------------------------------------------------------------------------- /graph/BFS/BFS.swift: -------------------------------------------------------------------------------- 1 | // MARK: - Basic requirement 2 | struct Edge { 3 | let from: Int 4 | let to: Int 5 | } 6 | 7 | public class Node { 8 | var val: Int 9 | var neighbors: [Int] 10 | public init(_ val: Int) { 11 | self.val = val 12 | self.neighbors = [] 13 | } 14 | } 15 | 16 | // MARK: - BFS implementation 17 | func testBFS(edges: [Edge]) { 18 | 19 | var graph = [Int: Node]() 20 | for edge in edges { 21 | graph[edge.from] = Node(edge.from) 22 | graph[edge.to] = Node(edge.to) 23 | } 24 | for edge in edges { 25 | graph[edge.from]?.neighbors.append(edge.to) 26 | graph[edge.to]?.neighbors.append(edge.from) 27 | } 28 | var visited: [Bool] = Array(repeating: false, count: graph.count + 1) 29 | var nodesOfCurrentLevel: [Int] = [] 30 | 31 | for node in 1...graph.count { 32 | if visited[node] == false { 33 | nodesOfCurrentLevel.append(node) 34 | while(nodesOfCurrentLevel.isEmpty == false) { 35 | var nodesOfNextLevel: [Int] = [] 36 | let sizeOfQueue = nodesOfCurrentLevel.count 37 | for index in 0.. 1 else { 11 | return 12 | } 13 | 14 | _quickSort(from: 0, to: count - 1) 15 | } 16 | 17 | mutating private func _quickSort(from left: Int, to right: Int) { 18 | guard left < right, right - left > 0 else { 19 | return 20 | } 21 | 22 | let pivotIndex = partition(from: left, to: right) 23 | _quickSort(from: left, to: pivotIndex - 1) 24 | _quickSort(from: pivotIndex + 1, to: right) 25 | } 26 | 27 | /// This method is where the pivot is chosen, so the smaller elements get moved to the left, 28 | /// and the bigger ones to the right. 29 | mutating private func partition(from left: Int, to right: Int) -> Int { 30 | /// Chooses the pivot, which in this case is always the first element, which is not very efficient. 31 | let pivotIndex = left 32 | swapAt(pivotIndex, right) 33 | 34 | let pivot = self[right] 35 | var i = left 36 | 37 | for j in i ..< right { 38 | // If the element is smaller than the pivot, move it to the left. 39 | if self[j] <= pivot { 40 | swapAt(i, j) 41 | i += 1 42 | } 43 | } 44 | 45 | // Move the pivot to its right sorted position. 46 | swapAt(i, right) 47 | 48 | return i 49 | } 50 | 51 | /// Returns a sorted version of this array using the QuickSort algorithm. 52 | func quickSorted() -> Array { 53 | var copy = self 54 | 55 | copy.quickSort() 56 | 57 | return copy 58 | } 59 | } 60 | 61 | // Use the following code to test it: 62 | // var numbers = [1002, 42, 55, 124, 205] 63 | // debugPrint(numbers.quickSorted()) 64 | // 65 | // numbers.quickSort() 66 | // debugPrint(numbers) 67 | // 68 | // The console should print: 69 | // [42, 55, 124, 205, 1002] 70 | // [42, 55, 124, 205, 1002] 71 | -------------------------------------------------------------------------------- /.github/workflows/.stale.yml: -------------------------------------------------------------------------------- 1 | # Configuration for probot-stale - https://github.com/probot/stale 2 | 3 | # Number of days of inactivity before an Issue or Pull Request becomes stale 4 | daysUntilStale: 30 5 | 6 | # Number of days of inactivity before an Issue or Pull Request with the stale label is closed. 7 | # Set to false to disable. If disabled, issues still need to be closed manually, but will remain marked as stale. 8 | daysUntilClose: 7 9 | 10 | # Only issues or pull requests with all of these labels are check if stale. Defaults to `[]` (disabled) 11 | onlyLabels: [] 12 | 13 | # Issues or Pull Requests with these labels will never be considered stale. Set to `[]` to disable 14 | exemptLabels: 15 | - "Status: on hold" 16 | 17 | # Set to true to ignore issues in a project (defaults to false) 18 | exemptProjects: false 19 | 20 | # Set to true to ignore issues in a milestone (defaults to false) 21 | exemptMilestones: false 22 | 23 | # Set to true to ignore issues with an assignee (defaults to false) 24 | exemptAssignees: false 25 | 26 | # Label to use when marking as stale 27 | staleLabel: stale 28 | 29 | # Comment to post when removing the stale label. 30 | # unmarkComment: > 31 | # Your comment here. 32 | 33 | # Optionally, specify configuration settings that are specific to just 'issues' or 'pulls': 34 | pulls: 35 | # Comment to post when marking as stale. Set to `false` to disable 36 | markComment: > 37 | This pull request has been automatically marked as stale because it has not had 38 | recent activity. It will be closed if no further activity occurs. Thank you 39 | for your contributions. 40 | # Comment to post when closing a stale Pull Request. 41 | closeComment: > 42 | Please reopen this pull request once you commit the changes requested 43 | or make improvements on the code. If this is not the case and you need 44 | some help, feel free to seek help from our [Gitter](https://gitter.im/TheAlgorithms) 45 | or ping one of the reviewers. Thank you for your contributions! 46 | issues: 47 | # Comment to post when marking as stale. Set to `false` to disable 48 | markComment: > 49 | This issue has been automatically marked as stale because it has not had 50 | recent activity. It will be closed if no further activity occurs. Thank you 51 | for your contributions. 52 | # Comment to post when closing a stale Issue. 53 | closeComment: > 54 | Please reopen this issue once you add more information and updates here. 55 | If this is not the case and you need some help, feel free to seek help 56 | from our [Gitter](https://gitter.im/TheAlgorithms) or ping one of the 57 | reviewers. Thank you for your contributions! 58 | -------------------------------------------------------------------------------- /algorithms/AI/minimax/Sources/Tests/Tests/MinimaxTests.swift: -------------------------------------------------------------------------------- 1 | import XCTest 2 | 3 | class MinimaxTests: XCTestCase { 4 | override func setUp() { 5 | super.setUp() 6 | } 7 | 8 | override func tearDown() { 9 | super.tearDown() 10 | } 11 | 12 | func testEvaluateGameState() { 13 | var board = Board(size: 3) 14 | let firstPlayer = Player(type: .human, symbol: .cross) 15 | let secondPlayer = Player(type: .human, symbol: .circle) 16 | 17 | board.clear() 18 | 19 | XCTAssertEqual(evaluateGameState(board: board, player: firstPlayer, opponent: secondPlayer), nil) 20 | 21 | board.makeMove(player: firstPlayer, position: Position(0, 0)) 22 | 23 | XCTAssertEqual(evaluateGameState(board: board, player: firstPlayer, opponent: secondPlayer), nil) 24 | 25 | board.makeMove(player: firstPlayer, position: Position(0, 1)) 26 | board.makeMove(player: firstPlayer, position: Position(0, 2)) 27 | 28 | XCTAssertEqual(evaluateGameState(board: board, player: firstPlayer, opponent: secondPlayer), .max) 29 | XCTAssertEqual(evaluateGameState(board: board, player: secondPlayer, opponent: firstPlayer), .min) 30 | 31 | board.clear() 32 | board.makeMove(player: secondPlayer, position: Position(0, 0)) 33 | board.makeMove(player: secondPlayer, position: Position(0, 1)) 34 | board.makeMove(player: secondPlayer, position: Position(0, 2)) 35 | board.makeMove(player: firstPlayer, position: Position(1, 0)) 36 | 37 | XCTAssertEqual(evaluateGameState(board: board, player: firstPlayer, opponent: secondPlayer), .min) 38 | XCTAssertEqual(evaluateGameState(board: board, player: secondPlayer, opponent: firstPlayer), .max) 39 | 40 | board.clear() 41 | board.makeMove(player: firstPlayer, position: Position(0, 0)) 42 | board.makeMove(player: secondPlayer, position: Position(0, 1)) 43 | board.makeMove(player: secondPlayer, position: Position(0, 2)) 44 | 45 | board.makeMove(player: secondPlayer, position: Position(1, 0)) 46 | board.makeMove(player: firstPlayer, position: Position(1, 1)) 47 | board.makeMove(player: firstPlayer, position: Position(1, 2)) 48 | 49 | board.makeMove(player: secondPlayer, position: Position(2, 0)) 50 | board.makeMove(player: firstPlayer, position: Position(2, 1)) 51 | board.makeMove(player: secondPlayer, position: Position(2, 2)) 52 | 53 | XCTAssertEqual(evaluateGameState(board: board, player: firstPlayer, opponent: secondPlayer), .null) 54 | XCTAssertEqual(evaluateGameState(board: board, player: secondPlayer, opponent: firstPlayer), .null) 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /algorithms/parsing/shunting_yard/shunting_yard.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | enum ShuntingYard { 4 | enum Operator: String, CaseIterable { 5 | case power = "^" 6 | case plus = "+" 7 | case minus = "-" 8 | case times = "*" 9 | case divide = "/" 10 | } 11 | 12 | static func evaluate(_ string: String) -> Double { 13 | let scanner = Scanner(string: string) 14 | var numberStack: [Double] = [] 15 | var operatorStack: [Operator] = [] 16 | 17 | func applyOperator(_ op: Operator) { 18 | guard let a = numberStack.popLast(), let b = numberStack.popLast() else { 19 | return 20 | } 21 | 22 | numberStack.append(op.apply(a, b)) 23 | } 24 | 25 | while !scanner.isAtEnd { 26 | if let op = scanner.scanOperator() { 27 | while let last = operatorStack.last, last.precedence > op.precedence || (op.leftAssociative && last.precedence == op.precedence) { 28 | applyOperator(last) 29 | operatorStack.removeLast() 30 | } 31 | operatorStack.append(op) 32 | } else if let number = scanner.scanDouble() { 33 | numberStack.append(number) 34 | } else { 35 | break 36 | } 37 | } 38 | 39 | while let op = operatorStack.popLast() { 40 | applyOperator(op) 41 | } 42 | 43 | return numberStack.first ?? 0 44 | } 45 | } 46 | 47 | extension ShuntingYard.Operator { 48 | var precedence: Int { 49 | switch self { 50 | case .power: return 3 51 | case .divide, .times: return 2 52 | case .plus, .minus: return 1 53 | } 54 | } 55 | 56 | var leftAssociative: Bool { 57 | switch self { 58 | case .power: return false 59 | case .plus, .minus, .times, .divide: return true 60 | } 61 | } 62 | 63 | func apply(_ a: Double, _ b: Double) -> Double { 64 | switch self { 65 | case .power: return pow(b, a) 66 | case .divide: return b / a 67 | case .times: return a * b 68 | case .plus: return a + b 69 | case .minus: return b - a 70 | } 71 | } 72 | } 73 | 74 | private extension Scanner { 75 | func scanOperator() -> ShuntingYard.Operator? { 76 | for op in ShuntingYard.Operator.allCases { 77 | if scanString(op.rawValue) != nil { 78 | return op 79 | } 80 | } 81 | return nil 82 | } 83 | } 84 | 85 | func testShuntingYard() { 86 | func test(_ x: String) { 87 | print(x,"=", ShuntingYard.evaluate(x)) 88 | } 89 | 90 | test("3 + 4 * 5") 91 | test("4 * 5 + 3") 92 | test("2 ^ 3 ^ 4") 93 | test("10.5 - 4 * 5") 94 | test("2 + 3 ^ 4") 95 | test("2 * 3 ^ 4") 96 | test("3 ^ 4") 97 | } 98 | -------------------------------------------------------------------------------- /algorithms/AI/minimax/README.md: -------------------------------------------------------------------------------- 1 | # Minimax algorithm 2 | 3 |

4 | 5 | ## Runtime environment 6 | 7 | 8 | 9 | 10 | ## Table of contents 11 | * [General info](#general-info) 12 | * [Functionality](#functionality) 13 | * [Pseudocode](#pseudocode) 14 | * [Demo](#demo) 15 | * [Sources](#sources) 16 | 17 | ## General info 18 | It is an example of implementation and use ``minimax algorithm`` in ``Tic Tac Toe`` game. Minimax is an algorithm that searches deeply into all possible states in the game. There are two types of players in the algorithm. One that wants to maximize the state of the game and one that wants to minimaze the state of the game. There are three states in the tic-tac-toe game: 19 | - `` -1 `` - if the minimizing player wins 20 | - `` 0 `` - in case of a tie 21 | - `` 1 `` - if the maximizing player wins 22 | 23 | ``Alpha-beta prunning`` this is a method that interrupts the search of those branches that do not lead to win. Alpha for maximizing player and beta for minimizing player. Alpha-beta prunnings reduce the time complexity of the algorithm. 24 | 25 | Parameters: 26 | - ``searching depth`` - how many moves in depth is to be calculated by the algorithm 27 | 28 | Input: 29 | - ``actual board state`` - in the form of an array for players symbols (cross/circle) 30 | - ``two player symbols`` - cross / circle 31 | 32 | Output: 33 | - ``the best move for autonomus(AI) player`` - Position(row: Int, column: Int) 34 | 35 | ## Functionality 36 | - example of use in Swift Playground with interactive UIView 37 | - unit tests in XCode 38 | 39 | ## Pseudocode 40 | 41 | ``` 42 | function alphabeta(node, depth, α, β, maximizingPlayer) is 43 | if depth = 0 or node is a terminal node then 44 | return the heuristic value of node 45 | if maximizingPlayer then 46 | value := −∞ 47 | for each child of node do 48 | value := max(value, alphabeta(child, depth − 1, α, β, FALSE)) 49 | if value ≥ β then 50 | break (* β cutoff *) 51 | α := max(α, value) 52 | return value 53 | else 54 | value := +∞ 55 | for each child of node do 56 | value := min(value, alphabeta(child, depth − 1, α, β, TRUE)) 57 | if value ≤ α then 58 | break (* α cutoff *) 59 | β := min(β, value) 60 | return value 61 | ``` 62 | 63 | ## Demo 64 | 65 |

66 | 67 | ## Sources 68 | * Minimax algorithm: https://en.wikipedia.org/wiki/Minimax 69 | * Alpha-beta prunning: https://en.wikipedia.org/wiki/Alpha–beta_pruning 70 | 71 | ## Author 72 | Written by Michał Nowak(mnowak061) 73 | -------------------------------------------------------------------------------- /data_structures/heap/heap.swift: -------------------------------------------------------------------------------- 1 | struct Heap { 2 | let compare: (Element, Element) -> Bool 3 | private var items : [Element] 4 | 5 | init(_ items : [Element], compare: @escaping (Element, Element) -> Bool) { 6 | self.compare = compare 7 | self.items = items 8 | for index in (0 ..< count / 2).reversed() { 9 | heapify(index) 10 | } 11 | } 12 | 13 | /// The minimum item on this heap or nil if the heap is empty 14 | var min: Element? { 15 | return items.first 16 | } 17 | 18 | /// The number of items on this heap 19 | var count: Int { 20 | return items.count 21 | } 22 | 23 | /// true if this heap is empty 24 | var isEmpty: Bool { 25 | return items.isEmpty 26 | } 27 | 28 | /// Removes and returns the minimum item from the heap. 29 | /// - returns: The minimum item from the heap or nil if the heap is empty. 30 | mutating func extractMin() -> Element? { 31 | guard let result = items.first else { return nil } 32 | 33 | items.removeFirst() 34 | heapify(0) 35 | return result 36 | 37 | } 38 | 39 | /// Inserts a new item into this heap 40 | /// - parameter item: The new item to insert 41 | mutating func insert(item : Element) { 42 | items.append(item) 43 | var i = items.count - 1 44 | while i > 0 && compare(items[i], items[parent(i)]) { 45 | items.swapAt(i, parent(i)) 46 | i = parent(i) 47 | } 48 | } 49 | 50 | /// Restores the heap property starting at a given index 51 | /// - parameter index: The index to start at 52 | private mutating func heapify(_ index : Int) { 53 | var minimumIndex = index 54 | if left(index) < count && compare(items[left(index)], items[minimumIndex]) { 55 | minimumIndex = left(index) 56 | } 57 | 58 | if right(index) < count && compare(items[right(index)], items[minimumIndex]) { 59 | minimumIndex = right(index) 60 | } 61 | 62 | if minimumIndex != index { 63 | items.swapAt(minimumIndex, index) 64 | heapify(minimumIndex) 65 | } 66 | } 67 | 68 | /// Returns the index of the left child of an item 69 | private func left(_ index : Int) -> Int { 70 | return 2 * index + 1 71 | } 72 | 73 | /// Returns the index of the right child of an item 74 | private func right(_ index: Int) -> Int { 75 | return 2 * index + 2 76 | } 77 | 78 | /// Returns the index of the parent of an item 79 | private func parent(_ index: Int) -> Int { 80 | return (index - 1) / 2 81 | } 82 | } 83 | 84 | 85 | extension Heap: ExpressibleByArrayLiteral where Element: Comparable { 86 | init(arrayLiteral elements: Element...) { 87 | self.init(elements, compare: <) 88 | } 89 | 90 | init(_ elements: [Element]) { 91 | self.init(elements, compare: <) 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /.github/workflows/directory_workflow.yml: -------------------------------------------------------------------------------- 1 | name: directory_md 2 | on: [push, pull_request] 3 | 4 | jobs: 5 | MainSequence: 6 | name: DIRECTORY.md 7 | runs-on: ubuntu-latest 8 | steps: 9 | - uses: actions/checkout@v1 # v2 is broken for git diff 10 | - uses: actions/setup-python@v2 11 | - name: Setup Git Specs 12 | run: | 13 | git config --global user.name github-actions 14 | git config --global user.email '${GITHUB_ACTOR}@users.noreply.github.com' 15 | git remote set-url origin https://x-access-token:${{ secrets.GITHUB_TOKEN }}@github.com/$GITHUB_REPOSITORY 16 | - name: Update DIRECTORY.md 17 | shell: python 18 | run: | 19 | import os 20 | from typing import Iterator 21 | URL_BASE = "https://github.com/TheAlgorithms/Swift/blob/master" 22 | g_output = [] 23 | def good_filepaths(top_dir: str = ".") -> Iterator[str]: 24 | fs_exts = tuple(".swift".split()) 25 | for dirpath, dirnames, filenames in os.walk(top_dir): 26 | dirnames[:] = [d for d in dirnames if d[0] not in "._"] 27 | for filename in filenames: 28 | if os.path.splitext(filename)[1].lower() in fs_exts: 29 | yield os.path.join(dirpath, filename).lstrip("./") 30 | def md_prefix(i): 31 | return f"{i * ' '}*" if i else "\n##" 32 | def print_path(old_path: str, new_path: str) -> str: 33 | global g_output 34 | old_parts = old_path.split(os.sep) 35 | for i, new_part in enumerate(new_path.split(os.sep)): 36 | if i + 1 > len(old_parts) or old_parts[i] != new_part: 37 | if new_part: 38 | g_output.append(f"{md_prefix(i)} {new_part.replace('_', ' ').title()}") 39 | return new_path 40 | def build_directory_md(top_dir: str = ".") -> str: 41 | global g_output 42 | old_path = "" 43 | for filepath in sorted(good_filepaths(), key=str.lower): 44 | filepath, filename = os.path.split(filepath) 45 | if filepath != old_path: 46 | old_path = print_path(old_path, filepath) 47 | indent = (filepath.count(os.sep) + 1) if filepath else 0 48 | url = "/".join((URL_BASE, filepath, filename)).replace(" ", "%20") 49 | filename = os.path.splitext(filename.replace("_", " ").title())[0] 50 | g_output.append(f"{md_prefix(indent)} [{filename}]({url})") 51 | return "# List of all files\n" + "\n".join(g_output) 52 | with open("DIRECTORY.md", "w") as out_file: 53 | out_file.write(build_directory_md(".") + "\n") 54 | - name: Commit DIRECTORY.md 55 | run: | 56 | git commit -m "updating DIRECTORY.md" DIRECTORY.md || true 57 | git diff DIRECTORY.md 58 | git push --force origin HEAD:$GITHUB_REF || true 59 | -------------------------------------------------------------------------------- /algorithms/AI/minimax/Sources/Minimax.playground/Sources/Model/GameModel/GameModel.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public class GameModel { 4 | // MARK: -- Public variable's 5 | public var board: Board! 6 | 7 | public var gameStatus: BoardStatus 8 | 9 | // MARK: -- Private variable's 10 | private var playersList: [Player]! 11 | 12 | private var movementsSequence: [Int]! 13 | 14 | private var actualPlayerIndex: Int! 15 | 16 | private var actualPlayer: Player { 17 | get { 18 | return playersList[actualPlayerIndex] 19 | } 20 | } 21 | 22 | private var difficultLevel: DifficultLevel = DifficultLevel.hard 23 | 24 | // MARK: -- Public function's 25 | public init(boardSize: Int, playersList: [Player], difficultLevel: DifficultLevel) { 26 | self.board = Board.init(size: boardSize) 27 | self.playersList = playersList 28 | self.difficultLevel = difficultLevel 29 | self.gameStatus = BoardStatus.continues 30 | 31 | self.generateMovementsSequence() 32 | self.changeActualPlayer() 33 | } 34 | 35 | public func update() { 36 | self.gameStatus = board.check(player: actualPlayer) 37 | 38 | switch self.gameStatus { 39 | case BoardStatus.continues: 40 | changeActualPlayer() 41 | case BoardStatus.draw: 42 | changeActualPlayer() 43 | default: break 44 | } 45 | } 46 | 47 | public func playerMakeMove(selectedPosition: (row: Int, column: Int)) { 48 | guard board.symbol(forPosition: selectedPosition) == PlayerSymbol.empty else { return } 49 | guard board.hasEmptyField() == true else { return } 50 | 51 | board.makeMove(player: actualPlayer, position: selectedPosition) 52 | update() 53 | } 54 | 55 | public func makeMinimaxMove() { 56 | guard actualPlayer.type == PlayerType.computer else { return } 57 | guard board.hasEmptyField() == true else { return } 58 | 59 | sleep(1) 60 | 61 | let selectedPosition: Position = minimaxMove(board: board, player: playersList[0], opponent: playersList[1], depth: self.difficultLevel.rawValue) 62 | board.makeMove(player: actualPlayer, position: selectedPosition) 63 | update() 64 | } 65 | 66 | public func newRound() { 67 | board.clear() 68 | gameStatus = BoardStatus.continues 69 | generateMovementsSequence() 70 | changeActualPlayer() 71 | } 72 | 73 | // MARK: -- Private function's 74 | private func generateMovementsSequence() { 75 | self.movementsSequence = [] 76 | 77 | let playersCount = playersList.count 78 | let movesCount = (board.size * board.size) 79 | 80 | var move = Int.random(in: 0 ..< playersCount) 81 | movementsSequence.append(move) 82 | 83 | for _ in 0 ..< movesCount - 1 { 84 | move += 1 85 | movementsSequence.append(move % playersCount) 86 | } 87 | } 88 | 89 | private func changeActualPlayer() { 90 | if !movementsSequence.isEmpty { 91 | actualPlayerIndex = movementsSequence.first! 92 | movementsSequence.removeFirst() 93 | } 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /graph/Graph.swift: -------------------------------------------------------------------------------- 1 | struct GraphEdge { 2 | var from: G.Node 3 | var to: G.Node 4 | var value: G.EdgeValue 5 | } 6 | 7 | protocol Graph { 8 | typealias Edge = GraphEdge 9 | 10 | associatedtype Node: Equatable 11 | associatedtype EdgeValue 12 | 13 | func edges(from: Node) -> [Edge] 14 | } 15 | 16 | struct AdjacencyList: Graph { 17 | typealias EdgeValue = EdgeValue 18 | typealias Node = Node 19 | 20 | var graph: [Node: [Edge]] = [:] 21 | 22 | func edges(from node: Node) -> [Edge] { 23 | graph[node, default: []] 24 | } 25 | 26 | mutating func insert(from: Node, to: Node, value: EdgeValue) { 27 | graph[from, default: []].append(Edge(from: from, to: to, value: value)) 28 | } 29 | 30 | var allEdges: [Edge] { 31 | graph.values.flatMap { $0 } 32 | } 33 | } 34 | 35 | extension AdjacencyList where EdgeValue == () { 36 | mutating func insert(from: Node, to: Node) { 37 | insert(from: from, to: to, value: ()) 38 | } 39 | } 40 | 41 | extension Graph { 42 | func depthFirstSearch(start: Node, destination: Node) -> [Edge]? { 43 | if start == destination { 44 | return [] 45 | } 46 | 47 | for edge in edges(from: start) { 48 | if let path = depthFirstSearch(start: edge.to, destination: destination) { 49 | return [edge] + path 50 | } 51 | } 52 | 53 | return nil 54 | } 55 | } 56 | 57 | extension Graph where Node: Hashable { 58 | func breadthFirstSearch(start: Node, destination: Node) -> [Edge]? { 59 | var queue: [(Node, [Edge])] = [(start, [])] 60 | var visited: Set = [start] 61 | 62 | while !queue.isEmpty { 63 | let (current, path) = queue.removeFirst() 64 | if current == destination { 65 | return path 66 | } 67 | 68 | for edge in edges(from: current) where visited.insert(edge.to).inserted { 69 | queue.append((edge.to, path + [edge])) 70 | } 71 | } 72 | 73 | return nil 74 | } 75 | } 76 | 77 | extension GraphEdge: CustomDebugStringConvertible { 78 | var debugDescription: String { 79 | if type(of: value) == Void.self { 80 | return "\(from) -- \(to)" 81 | } else { 82 | return "\(from) -\(value)- \(to)" 83 | } 84 | } 85 | } 86 | 87 | var graph = AdjacencyList() 88 | graph.insert(from: "a", to: "b") 89 | graph.insert(from: "a", to: "d") 90 | graph.insert(from: "b", to: "c") 91 | graph.insert(from: "c", to: "d") 92 | 93 | func test(_ message: String, _ list: [GraphEdge]?) { 94 | print(message) 95 | if let list = list { 96 | for edge in list { 97 | print(edge) 98 | } 99 | } else { 100 | print("Not found") 101 | } 102 | print("") 103 | } 104 | 105 | test("Depth-first a -> d", graph.depthFirstSearch(start: "a", destination: "d")) 106 | test("Depth-first a -> e", graph.depthFirstSearch(start: "a", destination: "e")) 107 | 108 | test("Breadth-first a -> d", graph.breadthFirstSearch(start: "a", destination: "d")) 109 | test("Breadth-first a -> e", graph.breadthFirstSearch(start: "a", destination: "e")) 110 | -------------------------------------------------------------------------------- /graph/spanning_tree/dijkstra.swift: -------------------------------------------------------------------------------- 1 | class Node : CustomStringConvertible { 2 | // unique identifier required for each node 3 | var identifier : Int 4 | var distance : Int = Int.max 5 | var edges = [Edge]() 6 | var visited = false 7 | 8 | var description: String { 9 | var edgesString = String() 10 | edges.forEach{ edgesString.append($0.description)} 11 | return "{ Node, identifier: \(identifier.description) + Edges: \(edgesString) + }" 12 | } 13 | 14 | init(visited: Bool, identifier: Int, edges: [Edge]) { 15 | self.visited = visited 16 | self.identifier = identifier 17 | self.edges = edges 18 | } 19 | 20 | static func == (lhs: Node, rhs: Node) -> Bool { 21 | return lhs.identifier == rhs.identifier 22 | } 23 | } 24 | 25 | class Edge { 26 | var from: Node // does not actually need to be stored! 27 | var to: Node 28 | var weight: Int 29 | var description : String { 30 | return "{ Edge, from: \(from.identifier), to: \(to.identifier), weight: \(weight) }" 31 | 32 | } 33 | init(to: Node, from: Node, weight: Int) { 34 | self.to = to 35 | self.weight = weight 36 | self.from = from 37 | } 38 | } 39 | 40 | class Graph { 41 | var nodes: [Node] = [] 42 | } 43 | 44 | 45 | // Complete the quickestWayUp function below. 46 | func setupGraphwith(edges: [[Int]]) -> Graph { 47 | let graph = Graph() 48 | 49 | // create all the nodes 50 | // The first and last node need to be included, so need nodes from "to" and "from" 51 | let nodeNames = Set ( edges.map{ $0[0] } + edges.map{ $0[1]} ) 52 | for node in nodeNames { 53 | let newNode = Node(visited: false, identifier: node, edges: []) 54 | graph.nodes.append(newNode) 55 | } 56 | 57 | // create all the edges to link the nodes 58 | for edge in edges { 59 | if let fromNode = graph.nodes.first(where: { $0.identifier == edge[0] }) { 60 | if let toNode = graph.nodes.first(where: { $0.identifier == edge[1] }) { 61 | let forwardEdge = Edge(to: toNode, from: fromNode, weight: edge[2]) 62 | fromNode.edges.append(forwardEdge) 63 | } 64 | } 65 | } 66 | return graph 67 | } 68 | 69 | func shortestPath (source: Int, destination: Int, graph: Graph) -> Int { 70 | 71 | var currentNode = graph.nodes.first{ $0.identifier == source }! 72 | currentNode.visited = true 73 | currentNode.distance = 0 74 | var toVisit = [Node]() 75 | toVisit.append(currentNode) 76 | while ( !toVisit.isEmpty) { 77 | toVisit = toVisit.filter{ $0.identifier != currentNode.identifier } 78 | currentNode.visited = true 79 | // Go to each adjacent vertex and update the path length 80 | for connectedEdge in currentNode.edges { 81 | let dist = currentNode.distance + connectedEdge.weight 82 | 83 | if (dist < connectedEdge.to.distance) { 84 | 85 | connectedEdge.to.distance = dist 86 | toVisit.append(connectedEdge.to) 87 | if (connectedEdge.to.visited == true) { 88 | 89 | connectedEdge.to.visited = false 90 | } 91 | } 92 | } 93 | 94 | currentNode.visited = true 95 | //set current node to the smallest vertex 96 | if !toVisit.isEmpty { 97 | currentNode = toVisit.min(by: { (a, b) -> Bool in 98 | return a.distance < b.distance 99 | })! 100 | } 101 | 102 | if (currentNode.identifier == destination) { 103 | return currentNode.distance 104 | } 105 | } 106 | 107 | return -1 108 | } 109 | -------------------------------------------------------------------------------- /data_structures/Linked List/LinkedList.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public class Node { 4 | public var value: Value? 5 | public var next: Node? 6 | 7 | public init(value: Value? = nil, next: Node? = nil) { 8 | self.value = value 9 | self.next = next 10 | } 11 | } 12 | 13 | extension Node: CustomStringConvertible { 14 | public var description: String { 15 | guard let next = next else { 16 | return "\(String(describing: value))" 17 | } 18 | return "\(String(describing: value)) -> " + String(describing: next) + " " 19 | } 20 | } 21 | 22 | public struct LinkedList { 23 | 24 | public var head: Node? 25 | public var tail: Node? 26 | 27 | public init() {} 28 | 29 | public var isEmpty: Bool { 30 | return head == nil 31 | } 32 | public mutating func push(_ value: Value) { 33 | head = Node(value: value, next: head) 34 | 35 | if tail == nil { 36 | tail = head 37 | } 38 | } 39 | 40 | public mutating func append(_ value: Value) { 41 | guard !isEmpty else { 42 | push(value) 43 | return 44 | } 45 | 46 | tail!.next = Node(value: value) 47 | 48 | tail = tail!.next 49 | } 50 | 51 | public func node(at index: Int) -> Node? { 52 | var currentNode = head 53 | var currentIndex = 0 54 | 55 | while currentNode != nil && currentIndex < index { 56 | currentNode = currentNode!.next 57 | currentIndex += 1 58 | } 59 | 60 | return currentNode 61 | } 62 | 63 | @discardableResult 64 | public mutating func insert(_ value: Value, 65 | after node: Node) -> Node { 66 | guard tail !== node else { 67 | append(value) 68 | return tail! 69 | } 70 | node.next = Node(value: value, next: node.next) 71 | 72 | return node.next! 73 | } 74 | 75 | @discardableResult 76 | public mutating func pop() -> Value? { 77 | defer { 78 | head = head?.next 79 | if isEmpty { 80 | tail = nil 81 | } 82 | } 83 | return head?.value 84 | } 85 | 86 | @discardableResult 87 | public mutating func removeLast() -> Value? { 88 | guard let head = head else { 89 | return nil 90 | } 91 | guard head.next != nil else { 92 | return pop() 93 | } 94 | var prev = head 95 | var current = head 96 | while let next = current.next { 97 | prev = current 98 | current = next 99 | } 100 | prev.next = nil 101 | tail = prev 102 | return current.value 103 | } 104 | 105 | @discardableResult 106 | public mutating func remove(after node: Node) -> Value? { 107 | defer { 108 | if node.next === tail { 109 | tail = node 110 | } 111 | node.next = node.next?.next 112 | } 113 | return node.next?.value 114 | } 115 | } 116 | 117 | extension LinkedList: CustomStringConvertible { 118 | public var description: String { 119 | guard let head = head else { 120 | return "Empty list" 121 | } 122 | return String(describing: head) 123 | } 124 | } 125 | 126 | // Below you can find a testing Scenario for Playground. 127 | 128 | /* 129 | import UIKit 130 | 131 | // Test Linked List 132 | 133 | let node1 = Node(value: 1) 134 | let node2 = Node(value: 2) 135 | let node3 = Node(value: 3) 136 | 137 | node1.next = node2 138 | node2.next = node3 139 | 140 | print(node1) 141 | 142 | var list = LinkedList() 143 | list.push(3) 144 | list.push(2) 145 | list.push(1) 146 | 147 | print(list) 148 | 149 | var listAppend = LinkedList() 150 | 151 | listAppend.append(1) 152 | listAppend.append(2) 153 | listAppend.append(3) 154 | 155 | print(listAppend) 156 | */ 157 | -------------------------------------------------------------------------------- /algorithms/AI/minimax/Sources/Minimax.playground/Sources/Model/Minimax/Minimax.swift: -------------------------------------------------------------------------------- 1 | public func minimaxMove(board: Board, player: Player, opponent: Player, depth: Int) -> Position { 2 | var bestVal = GameStateValue.min 3 | var bestMoves: [Position] = [] 4 | 5 | for i in 0 ..< board.size { 6 | for j in 0 ..< board.size { 7 | if board.symbol(forPosition: Position(i, j)) == PlayerSymbol.empty { 8 | var tempBoard = board 9 | let move = Position(i, j) 10 | 11 | tempBoard.makeMove(player: opponent, position: (i, j)) 12 | let moveVal = minMax(board: tempBoard, player: opponent, opponent: player, 13 | depth: depth, 14 | alpha: GameStateValue.min.rawValue, beta: GameStateValue.max.rawValue, 15 | maximizingPlayer: false) 16 | 17 | if moveVal.rawValue > bestVal.rawValue { 18 | bestVal = moveVal 19 | bestMoves = [] 20 | bestMoves.append(move) 21 | } else if moveVal == bestVal { 22 | bestMoves.append(move) 23 | } 24 | } 25 | } 26 | } 27 | 28 | return bestMoves[Int.random(in: 0 ..< bestMoves.count)] 29 | } 30 | 31 | public func minMax(board: Board, player: Player, opponent: Player, depth: Int, alpha: Int, beta: Int, maximizingPlayer: Bool) -> GameStateValue { 32 | var alpha = alpha 33 | var beta = beta 34 | 35 | if let gameResult = evaluateGameState(board: board, player: player, opponent: opponent) { 36 | guard depth != 0 && gameResult != GameStateValue.min && gameResult != GameStateValue.max && gameResult != GameStateValue.null else { 37 | return gameResult 38 | } 39 | } 40 | 41 | if maximizingPlayer { 42 | var maxEval = GameStateValue.min 43 | 44 | for i in 0 ..< board.size { 45 | for j in 0 ..< board.size { 46 | if board.symbol(forPosition: Position(i, j)) == PlayerSymbol.empty { 47 | var tempBoard = board 48 | tempBoard.makeMove(player: player, position: Position(i, j)) 49 | 50 | let eval = minMax(board: tempBoard, player: player, opponent: opponent, depth: depth - 1, 51 | alpha: alpha, beta: beta, 52 | maximizingPlayer: !maximizingPlayer) 53 | 54 | maxEval = GameStateValue(rawValue: max(maxEval.rawValue, eval.rawValue))! 55 | alpha = max(alpha, eval.rawValue) 56 | 57 | if beta <= alpha { break } 58 | } 59 | } 60 | } 61 | 62 | return maxEval 63 | } else { 64 | var minEval = GameStateValue.max 65 | 66 | for i in 0 ..< board.size { 67 | for j in 0 ..< board.size { 68 | if board.symbol(forPosition: Position(i, j)) == PlayerSymbol.empty { 69 | var tempBoard = board 70 | tempBoard.makeMove(player: opponent, position: (i, j)) 71 | 72 | let eval = minMax(board: tempBoard, player: player, opponent: opponent, depth: depth - 1, 73 | alpha: alpha, beta: beta, 74 | maximizingPlayer: !maximizingPlayer) 75 | 76 | minEval = GameStateValue(rawValue: min(minEval.rawValue, eval.rawValue))! 77 | beta = min(beta, eval.rawValue) 78 | 79 | if beta <= alpha { break } 80 | } 81 | } 82 | } 83 | 84 | return minEval 85 | } 86 | } 87 | 88 | public func evaluateGameState(board: Board, player: Player, opponent: Player) -> GameStateValue? { 89 | if board.check(player: player) == BoardStatus.win { 90 | return GameStateValue.max 91 | } else if board.check(player: opponent) == BoardStatus.win { 92 | return GameStateValue.min 93 | } else if board.check(player: player) == BoardStatus.draw || board.check(player: opponent) == BoardStatus.draw { 94 | return GameStateValue.null 95 | } 96 | 97 | return nil 98 | } 99 | -------------------------------------------------------------------------------- /algorithms/AI/minimax/Sources/Tests/Tests/BoardTests.swift: -------------------------------------------------------------------------------- 1 | import XCTest 2 | 3 | class BoardTests: XCTestCase { 4 | 5 | private var sut: Board! 6 | 7 | private var boardSize = 3 8 | 9 | override func setUp() { 10 | super.setUp() 11 | sut = Board(size: boardSize) 12 | } 13 | 14 | override func tearDown() { 15 | sut = nil 16 | super.tearDown() 17 | } 18 | 19 | func testInit() { 20 | XCTAssertEqual(sut.size, boardSize) 21 | XCTAssertEqual(allFieldsAreEmpty(), true) 22 | } 23 | 24 | func testSymbolForPosition() { 25 | let player = Player(type: .human, symbol: .circle) 26 | let position = Position(0, 0) 27 | 28 | sut.clear() 29 | XCTAssertEqual(sut.symbol(forPosition: position), PlayerSymbol.empty) 30 | 31 | sut.makeMove(player: player, position: position) 32 | XCTAssertEqual(sut.symbol(forPosition: position), player.symbol) 33 | } 34 | 35 | func testClear() { 36 | let player = Player(type: .computer, symbol: .circle) 37 | let position = Position(0, 0) 38 | 39 | sut.makeMove(player: player, position: position) 40 | 41 | XCTAssertEqual(allFieldsAreEmpty(), false) 42 | 43 | sut.clear() 44 | 45 | XCTAssertEqual(allFieldsAreEmpty(), true) 46 | } 47 | 48 | func testHasEmptyField() { 49 | let player = Player(type: .computer, symbol: .circle) 50 | 51 | sut.clear() 52 | 53 | XCTAssertEqual(sut.hasEmptyField(), true) 54 | 55 | sut.makeMove(player: player, position: Position(0, 0)) 56 | sut.makeMove(player: player, position: Position(0, 1)) 57 | sut.makeMove(player: player, position: Position(0, 2)) 58 | 59 | sut.makeMove(player: player, position: Position(1, 0)) 60 | sut.makeMove(player: player, position: Position(1, 1)) 61 | sut.makeMove(player: player, position: Position(1, 2)) 62 | 63 | sut.makeMove(player: player, position: Position(2, 0)) 64 | sut.makeMove(player: player, position: Position(2, 1)) 65 | sut.makeMove(player: player, position: Position(2, 2)) 66 | 67 | XCTAssertEqual(sut.hasEmptyField(), false) 68 | } 69 | 70 | func testMakeMove() { 71 | let firstPlayer = Player(type: .human, symbol: .circle) 72 | let secondPlayer = Player(type: .human, symbol: .cross) 73 | let position = Position(0, 0) 74 | 75 | sut.clear() 76 | sut.makeMove(player: firstPlayer, position: position) 77 | sut.makeMove(player: secondPlayer, position: position) 78 | 79 | XCTAssertEqual(sut.symbol(forPosition: position), firstPlayer.symbol) 80 | } 81 | 82 | func testCheck() { 83 | let firstPlayer = Player(type: .computer, symbol: .circle) 84 | let secondPlayer = Player(type: .computer, symbol: .cross) 85 | 86 | sut.clear() 87 | 88 | XCTAssertEqual(sut.check(player: firstPlayer), BoardStatus.continues) 89 | XCTAssertEqual(sut.check(player: secondPlayer), BoardStatus.continues) 90 | 91 | sut.clear() 92 | sut.makeMove(player: firstPlayer, position: Position(0, 0)) 93 | sut.makeMove(player: firstPlayer, position: Position(0, 1)) 94 | sut.makeMove(player: firstPlayer, position: Position(0, 2)) 95 | 96 | XCTAssertEqual(sut.check(player: firstPlayer), BoardStatus.win) 97 | XCTAssertEqual(sut.check(player: secondPlayer), BoardStatus.continues) 98 | 99 | sut.clear() 100 | sut.makeMove(player: firstPlayer, position: Position(0, 0)) 101 | sut.makeMove(player: firstPlayer, position: Position(1, 0)) 102 | sut.makeMove(player: firstPlayer, position: Position(2, 0)) 103 | 104 | XCTAssertEqual(sut.check(player: firstPlayer), BoardStatus.win) 105 | XCTAssertEqual(sut.check(player: secondPlayer), BoardStatus.continues) 106 | 107 | sut.clear() 108 | sut.makeMove(player: firstPlayer, position: Position(0, 0)) 109 | sut.makeMove(player: firstPlayer, position: Position(1, 1)) 110 | sut.makeMove(player: firstPlayer, position: Position(2, 2)) 111 | 112 | XCTAssertEqual(sut.check(player: firstPlayer), BoardStatus.win) 113 | XCTAssertEqual(sut.check(player: secondPlayer), BoardStatus.continues) 114 | 115 | sut.clear() 116 | sut.makeMove(player: firstPlayer, position: Position(0, 0)) 117 | sut.makeMove(player: secondPlayer, position: Position(0, 1)) 118 | sut.makeMove(player: secondPlayer, position: Position(0, 2)) 119 | 120 | sut.makeMove(player: secondPlayer, position: Position(1, 0)) 121 | sut.makeMove(player: firstPlayer, position: Position(1, 1)) 122 | sut.makeMove(player: firstPlayer, position: Position(1, 2)) 123 | 124 | sut.makeMove(player: secondPlayer, position: Position(2, 0)) 125 | sut.makeMove(player: firstPlayer, position: Position(2, 1)) 126 | sut.makeMove(player: secondPlayer, position: Position(2, 2)) 127 | 128 | XCTAssertEqual(sut.check(player: firstPlayer), BoardStatus.draw) 129 | XCTAssertEqual(sut.check(player: secondPlayer), BoardStatus.draw) 130 | } 131 | 132 | private func allFieldsAreEmpty() -> Bool { 133 | var allFieldAreEmpty = true 134 | 135 | for row in 0 ..< sut.size { 136 | for column in 0 ..< sut.size { 137 | if sut.symbol(forPosition: Position(row, column)) != PlayerSymbol.empty { 138 | allFieldAreEmpty = false 139 | } 140 | } 141 | } 142 | 143 | return allFieldAreEmpty 144 | } 145 | } 146 | -------------------------------------------------------------------------------- /algorithms/AI/minimax/Sources/Minimax.playground/Sources/Model/Board/Board.swift: -------------------------------------------------------------------------------- 1 | public struct Board { 2 | // MARK: -- Public variable's 3 | public var size: Int 4 | 5 | // MARK: -- Private variable's 6 | private var table: [ [PlayerSymbol?] ] 7 | 8 | // MARK: -- Public function's 9 | public init(size: Int) { 10 | self.size = size 11 | self.table = [] 12 | self.clear() 13 | } 14 | 15 | public mutating func clear() { 16 | self.table = Array(repeating: Array(repeating: PlayerSymbol.empty, count: size), count: size) 17 | } 18 | 19 | public func hasEmptyField() -> Bool { 20 | for i in 0 ..< self.size { 21 | for j in 0 ..< self.size { 22 | if self.table[i][j] == PlayerSymbol.empty { 23 | return true 24 | } 25 | } 26 | } 27 | return false 28 | } 29 | 30 | public func symbol(forPosition position: Position) -> PlayerSymbol? { 31 | guard position.row < self.size, position.column < size else { return nil } 32 | return self.table[position.row][position.column] 33 | } 34 | 35 | public mutating func makeMove(player: Player, position: Position) { 36 | guard self.symbol(forPosition: position) == PlayerSymbol.empty else { return } 37 | guard self.symbol(forPosition: position) != player.symbol else { return } 38 | 39 | self.table[position.row][position.column] = player.symbol 40 | } 41 | 42 | public func check(player: Player) -> BoardStatus { 43 | let playerSymbol: PlayerSymbol = player.symbol 44 | 45 | if self.foundWinInRows(playerSymbol) { return BoardStatus.win } 46 | if self.foundWinInColumns(playerSymbol) { return BoardStatus.win } 47 | if self.foundWinInSlants(playerSymbol) { return BoardStatus.win } 48 | 49 | if self.hasEmptyField() { return BoardStatus.continues } else { return BoardStatus.draw } 50 | } 51 | 52 | // MARK: -- Private function's 53 | private func foundWinInRows(_ playerSymbol: PlayerSymbol) -> Bool { 54 | for i in 0 ..< self.size { 55 | var theSameSymbolsInRowCount = 0 56 | 57 | for j in 0 ..< self.size - 1 { 58 | if self.table[i][j] == self.table[i][j+1] && (self.table[i][j] == playerSymbol) { 59 | theSameSymbolsInRowCount += 1 60 | } else { 61 | theSameSymbolsInRowCount = 0 62 | } 63 | } 64 | 65 | if theSameSymbolsInRowCount == self.size - 1 { 66 | return true 67 | } 68 | } 69 | 70 | return false 71 | } 72 | 73 | private func foundWinInColumns(_ playerSymbol: PlayerSymbol) -> Bool { 74 | for j in 0 ..< self.size { 75 | var theSameSymbolsInColumnCount = 0 76 | 77 | for i in 0 ..< self.size - 1 { 78 | if self.table[i][j] == self.table[i+1][j] && (self.table[i][j] == playerSymbol) { 79 | theSameSymbolsInColumnCount += 1 80 | } else { 81 | theSameSymbolsInColumnCount = 0 82 | } 83 | } 84 | 85 | if theSameSymbolsInColumnCount == self.size - 1 { 86 | return true 87 | } 88 | } 89 | 90 | return false 91 | } 92 | 93 | private func foundWinInSlants(_ playerSymbol: PlayerSymbol) -> Bool { 94 | var theSameSymbolsInSlantCount = 0 95 | 96 | for i in 0 ..< self.size { 97 | for j in -(self.size - 1) ... 0 { 98 | if(self.table[-j][i] == playerSymbol) { 99 | var k: Int = -j 100 | var l: Int = i 101 | theSameSymbolsInSlantCount = 0 102 | 103 | while l < self.size && k >= 0 { 104 | if self.table[k][l] == playerSymbol { 105 | theSameSymbolsInSlantCount += 1 106 | } else { 107 | theSameSymbolsInSlantCount = 0 108 | } 109 | k -= 1 110 | l += 1 111 | 112 | if theSameSymbolsInSlantCount == self.size { 113 | return true 114 | } 115 | } 116 | theSameSymbolsInSlantCount = 0 117 | } 118 | theSameSymbolsInSlantCount = 0 119 | } 120 | theSameSymbolsInSlantCount = 0 121 | } 122 | 123 | theSameSymbolsInSlantCount = 0 124 | 125 | for i in 0 ..< self.size { 126 | for j in 0 ..< self.size { 127 | if(self.table[j][i] == playerSymbol) { 128 | var k: Int = j 129 | var l: Int = i 130 | theSameSymbolsInSlantCount = 0 131 | 132 | while l < self.size && k < self.size { 133 | if self.table[k][l] == playerSymbol { 134 | theSameSymbolsInSlantCount += 1 135 | } else { 136 | theSameSymbolsInSlantCount = 0 137 | } 138 | k += 1 139 | l += 1 140 | 141 | if theSameSymbolsInSlantCount == self.size { 142 | return true 143 | } 144 | } 145 | theSameSymbolsInSlantCount = 0 146 | } 147 | theSameSymbolsInSlantCount = 0 148 | } 149 | theSameSymbolsInSlantCount = 0 150 | } 151 | 152 | return false 153 | } 154 | } 155 | -------------------------------------------------------------------------------- /data_structures/doubly_linked_list/DoublyLinkedList.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public class Node { 4 | public var value: Value? 5 | public var next: Node? 6 | public var prev: Node? 7 | 8 | public init(value: Value? = nil, next: Node? = nil, prev: Node? = nil) { 9 | self.value = value 10 | self.next = next 11 | self.prev = prev 12 | } 13 | } 14 | 15 | extension Node: CustomStringConvertible { 16 | public var description: String { 17 | guard let next: Node = self.next else { 18 | return "\(String(describing: value))" 19 | } 20 | return "\(String(describing: value)) <-> \(String(describing: next)) " 21 | } 22 | } 23 | 24 | public struct DoublyLinkedList { 25 | 26 | public var head: Node? 27 | public var tail: Node? 28 | public var count: Int = 0 29 | 30 | public var isEmpty: Bool { 31 | return head == nil 32 | } 33 | 34 | public mutating func push(_ value: Value) { 35 | let new: Node = Node(value: value, next: head) 36 | if head != nil { head!.prev = new } 37 | head = new 38 | if tail == nil { tail = head } 39 | count += 1 40 | } 41 | 42 | public mutating func append(_ value: Value) { 43 | guard !isEmpty else { 44 | push(value) 45 | return 46 | } 47 | tail!.next = Node(value: value, prev: tail) 48 | tail = tail!.next 49 | count += 1 50 | } 51 | 52 | @discardableResult 53 | public mutating func insert(_ value: Value, 54 | after node: Node) -> Node { 55 | guard tail !== node else { 56 | append(value) 57 | return tail! 58 | } 59 | var new: Node = Node(value: value, next: node.next, prev: node) 60 | node.next?.prev = new 61 | node.next = new 62 | count += 1 63 | return node.next! 64 | } 65 | 66 | @discardableResult 67 | public mutating func insert(_ value: Value, 68 | before node: Node) -> Node { 69 | guard head !== node else { 70 | push(value) 71 | return head! 72 | } 73 | var new: Node = Node(value: value, next: node, prev: node.prev) 74 | node.prev?.next = new 75 | node.prev = new 76 | count += 1 77 | return node.prev! 78 | } 79 | 80 | public func node(at index: Int) -> Node? { 81 | guard index > -1 || index < count else { return nil } 82 | 83 | let startFromTail: Bool = index > count / 2 84 | var currentNode: Node? = startFromTail ? tail : head 85 | var currentIndex: Int = startFromTail ? count - 1 : 0 86 | var change: Int = startFromTail ? -1 : 1 87 | 88 | while currentNode != nil { 89 | if currentIndex == index { break } 90 | currentNode = startFromTail ? currentNode!.prev : currentNode!.next 91 | currentIndex += change 92 | } 93 | 94 | return currentNode 95 | } 96 | 97 | @discardableResult 98 | public mutating func pop() -> Value? { 99 | defer { 100 | head = head?.next 101 | count -= 1 102 | if isEmpty { 103 | tail = nil 104 | } else { 105 | head!.prev = nil 106 | } 107 | } 108 | return head?.value 109 | } 110 | 111 | @discardableResult 112 | public mutating func removeLast() -> Value? { 113 | defer { 114 | tail = tail?.prev 115 | count -= 1 116 | if isEmpty { 117 | head = nil 118 | } else { 119 | tail!.next = nil 120 | } 121 | } 122 | return tail?.value 123 | } 124 | 125 | @discardableResult 126 | public mutating func remove(after node: Node) -> Value? { 127 | defer { 128 | if node.next != nil { 129 | count -= 1 130 | } 131 | if node.next === tail { 132 | tail = node 133 | } 134 | if let next2node: Node = node.next?.next { 135 | next2node.prev = node 136 | } 137 | node.next = node.next?.next 138 | } 139 | return node.next?.value 140 | } 141 | 142 | @discardableResult 143 | public mutating func remove(before node: Node) -> Value? { 144 | defer { 145 | if node.prev != nil { 146 | count -= 1 147 | } 148 | if node.prev === head { 149 | head = node 150 | } 151 | if let prev2node: Node = node.prev?.prev { 152 | prev2node.next = node 153 | } 154 | node.prev = node.prev?.prev 155 | } 156 | return node.prev?.value 157 | } 158 | } 159 | 160 | extension DoublyLinkedList: CustomStringConvertible { 161 | public var description: String { 162 | guard let head: Node = self.head else { 163 | return "Empty list" 164 | } 165 | return String(describing: head) 166 | } 167 | } 168 | 169 | // Here are testing scenarios to run in a Swift playground 170 | 171 | /* 172 | var list = DoublyLinkedList() 173 | 174 | list.push(4) 175 | list.push(2) 176 | list.push(1) 177 | 178 | list.append(6) 179 | 180 | var n = list.node(at: 2) 181 | 182 | list.insert(5, after: n!) 183 | list.insert(3, before: n!) 184 | 185 | print(list) 186 | 187 | print(list.pop()!) 188 | print(list.removeLast()!) 189 | 190 | print(list.remove(after: n!)!) 191 | print(list.remove(before: n!)!) 192 | 193 | print(list.count) 194 | */ 195 | -------------------------------------------------------------------------------- /DIRECTORY.md: -------------------------------------------------------------------------------- 1 | # List of all files 2 | 3 | ## Algorithms 4 | * Ai 5 | * Minimax 6 | * Sources 7 | * Minimax.Playground 8 | * [Contents](https://github.com/TheAlgorithms/Swift/blob/master/algorithms/AI/minimax/Sources/Minimax.playground/Contents.swift) 9 | * Sources 10 | * Model 11 | * Board 12 | * [Board](https://github.com/TheAlgorithms/Swift/blob/master/algorithms/AI/minimax/Sources/Minimax.playground/Sources/Model/Board/Board.swift) 13 | * [Boardposition](https://github.com/TheAlgorithms/Swift/blob/master/algorithms/AI/minimax/Sources/Minimax.playground/Sources/Model/Board/BoardPosition.swift) 14 | * [Boardstatus](https://github.com/TheAlgorithms/Swift/blob/master/algorithms/AI/minimax/Sources/Minimax.playground/Sources/Model/Board/BoardStatus.swift) 15 | * Gamemodel 16 | * [Difficultlevel](https://github.com/TheAlgorithms/Swift/blob/master/algorithms/AI/minimax/Sources/Minimax.playground/Sources/Model/GameModel/DifficultLevel.swift) 17 | * [Gamemodel](https://github.com/TheAlgorithms/Swift/blob/master/algorithms/AI/minimax/Sources/Minimax.playground/Sources/Model/GameModel/GameModel.swift) 18 | * Minimax 19 | * [Gamestatevalue](https://github.com/TheAlgorithms/Swift/blob/master/algorithms/AI/minimax/Sources/Minimax.playground/Sources/Model/Minimax/GameStateValue.swift) 20 | * [Minimax](https://github.com/TheAlgorithms/Swift/blob/master/algorithms/AI/minimax/Sources/Minimax.playground/Sources/Model/Minimax/Minimax.swift) 21 | * Player 22 | * [Player](https://github.com/TheAlgorithms/Swift/blob/master/algorithms/AI/minimax/Sources/Minimax.playground/Sources/Model/Player/Player.swift) 23 | * [Playersymbol](https://github.com/TheAlgorithms/Swift/blob/master/algorithms/AI/minimax/Sources/Minimax.playground/Sources/Model/Player/PlayerSymbol.swift) 24 | * [Playertype](https://github.com/TheAlgorithms/Swift/blob/master/algorithms/AI/minimax/Sources/Minimax.playground/Sources/Model/Player/PlayerType.swift) 25 | * View 26 | * [Boardview](https://github.com/TheAlgorithms/Swift/blob/master/algorithms/AI/minimax/Sources/Minimax.playground/Sources/View/BoardView.swift) 27 | * Tests 28 | * Tests 29 | * [Boardtests](https://github.com/TheAlgorithms/Swift/blob/master/algorithms/AI/minimax/Sources/Tests/Tests/BoardTests.swift) 30 | * [Minimaxtests](https://github.com/TheAlgorithms/Swift/blob/master/algorithms/AI/minimax/Sources/Tests/Tests/MinimaxTests.swift) 31 | * [Playertests](https://github.com/TheAlgorithms/Swift/blob/master/algorithms/AI/minimax/Sources/Tests/Tests/PlayerTests.swift) 32 | * Conversion 33 | * [Binary-To-Decimal](https://github.com/TheAlgorithms/Swift/blob/master/algorithms/conversion/binary-to-decimal.swift) 34 | * [Decimal-To-Binary](https://github.com/TheAlgorithms/Swift/blob/master/algorithms/conversion/decimal-to-binary.swift) 35 | * Palindrome 36 | * [Palindrome Indices](https://github.com/TheAlgorithms/Swift/blob/master/algorithms/palindrome/palindrome_indices.swift) 37 | * [Palindrome Recursion](https://github.com/TheAlgorithms/Swift/blob/master/algorithms/palindrome/palindrome_recursion.swift) 38 | * [Palindrome Reversed](https://github.com/TheAlgorithms/Swift/blob/master/algorithms/palindrome/palindrome_reversed.swift) 39 | * Parsing 40 | * Shunting Yard 41 | * [Shunting Yard](https://github.com/TheAlgorithms/Swift/blob/master/algorithms/parsing/shunting_yard/shunting_yard.swift) 42 | 43 | ## Data Structures 44 | * Doubly Linked List 45 | * [Doublylinkedlist](https://github.com/TheAlgorithms/Swift/blob/master/data_structures/doubly_linked_list/DoublyLinkedList.swift) 46 | * Heap 47 | * [Heap](https://github.com/TheAlgorithms/Swift/blob/master/data_structures/heap/heap.swift) 48 | * Linked List 49 | * [Linkedlist](https://github.com/TheAlgorithms/Swift/blob/master/data_structures/Linked%20List/LinkedList.swift) 50 | * Queue 51 | * [Queue](https://github.com/TheAlgorithms/Swift/blob/master/data_structures/queue/queue.swift) 52 | * Stack 53 | * [Stack](https://github.com/TheAlgorithms/Swift/blob/master/data_structures/Stack/stack.swift) 54 | * Union Find 55 | * [Union Find](https://github.com/TheAlgorithms/Swift/blob/master/data_structures/union_find/union_find.swift) 56 | 57 | ## Graph 58 | * Bfs 59 | * [Bfs](https://github.com/TheAlgorithms/Swift/blob/master/graph/BFS/BFS.swift) 60 | * Dfs 61 | * [Dfs](https://github.com/TheAlgorithms/Swift/blob/master/graph/DFS/DFS.swift) 62 | * [Graph](https://github.com/TheAlgorithms/Swift/blob/master/graph/Graph.swift) 63 | * Spanning Tree 64 | * [Dijkstra](https://github.com/TheAlgorithms/Swift/blob/master/graph/spanning_tree/dijkstra.swift) 65 | * [Kruskal](https://github.com/TheAlgorithms/Swift/blob/master/graph/spanning_tree/kruskal.swift) 66 | 67 | ## Recursion 68 | * [Fibonacci](https://github.com/TheAlgorithms/Swift/blob/master/recursion/fibonacci.swift) 69 | 70 | ## Search 71 | * [Binarysearch](https://github.com/TheAlgorithms/Swift/blob/master/Search/BinarySearch.swift) 72 | * [Linearsearch](https://github.com/TheAlgorithms/Swift/blob/master/Search/LinearSearch.swift) 73 | 74 | ## Sorts 75 | * [Bubblesort](https://github.com/TheAlgorithms/Swift/blob/master/sorts/BubbleSort.swift) 76 | * [Cocktailsort](https://github.com/TheAlgorithms/Swift/blob/master/sorts/CocktailSort.swift) 77 | * [Insertionsort](https://github.com/TheAlgorithms/Swift/blob/master/sorts/InsertionSort.swift) 78 | * [Mergesort](https://github.com/TheAlgorithms/Swift/blob/master/sorts/MergeSort.swift) 79 | * [Pancakesort](https://github.com/TheAlgorithms/Swift/blob/master/sorts/PancakeSort.swift) 80 | * [Quicksort](https://github.com/TheAlgorithms/Swift/blob/master/sorts/QuickSort.swift) 81 | * [Selectionsort](https://github.com/TheAlgorithms/Swift/blob/master/sorts/SelectionSort.swift) 82 | 83 | ## Trees 84 | * [Tree](https://github.com/TheAlgorithms/Swift/blob/master/trees/tree.swift) 85 | -------------------------------------------------------------------------------- /algorithms/AI/minimax/Sources/Minimax.playground/Sources/View/BoardView.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | 3 | public class BoardView: UIView { 4 | // MARK: -- Public 5 | public var gameModel: GameModel! 6 | 7 | public var players = [Player(type: .human, symbol: .circle), 8 | Player(type: .computer, symbol: .cross)] 9 | 10 | // MARK: -- Override's 11 | public override init(frame: CGRect) { 12 | super.init(frame: frame) 13 | 14 | self.setupBoard() 15 | self.setupResetButton() 16 | self.setupIndicator() 17 | self.startGame() 18 | } 19 | 20 | required init?(coder: NSCoder) { 21 | super.init(coder: coder) 22 | } 23 | 24 | // MARK: -- Private 25 | private var buttons: [UIButton] = [] 26 | 27 | private var stackView: UIStackView! 28 | 29 | private var resetButton: UIButton! 30 | 31 | private var indicator: UIActivityIndicatorView! 32 | 33 | private func startGame() { 34 | self.gameModel = GameModel.init(boardSize: 3, playersList: self.players, difficultLevel: .hard) 35 | 36 | DispatchQueue.global(qos: .userInteractive).async { 37 | 38 | self.blockViewForUser() 39 | 40 | self.gameModel.makeMinimaxMove() 41 | 42 | self.unblockViewForUser() 43 | } 44 | } 45 | 46 | private func updateUI() { 47 | if gameModel.gameStatus != BoardStatus.continues { 48 | self.resetButton.setTitle("New game", for: .normal) 49 | blockButtons() 50 | } else { 51 | self.resetButton.setTitle("Reset", for: .normal) 52 | } 53 | boardToButtons() 54 | } 55 | 56 | private func boardToButtons() { 57 | var buttonIndex = 0 58 | 59 | for row in 0 ..< 3 { 60 | for column in 0 ..< 3 { 61 | let symbol = gameModel.board.symbol(forPosition: Position(row, column)) 62 | if symbol != PlayerSymbol.empty { 63 | self.buttons[buttonIndex].setTitle(symbol?.rawValue, for: .normal) 64 | self.buttons[buttonIndex].isUserInteractionEnabled = false 65 | } 66 | buttonIndex += 1 67 | } 68 | } 69 | } 70 | 71 | private func setupBoard() { 72 | self.stackView = UIStackView() 73 | self.stackView.translatesAutoresizingMaskIntoConstraints = false 74 | self.stackView.axis = .vertical 75 | self.stackView.alignment = .fill 76 | self.stackView.distribution = .fillEqually 77 | self.stackView.spacing = 10 78 | 79 | self.addSubview(self.stackView) 80 | 81 | for index in 1 ... 3 { 82 | let boardRow = self.createBoardRow(rowNumber: index) 83 | self.stackView.addArrangedSubview(boardRow) 84 | } 85 | 86 | // constraints 87 | let constraints = [ 88 | self.stackView.topAnchor.constraint(equalTo: self.topAnchor, constant: 10), 89 | self.stackView.centerXAnchor.constraint(equalTo: self.centerXAnchor), 90 | self.stackView.widthAnchor.constraint(equalTo: self.widthAnchor, constant: -20), 91 | self.stackView.heightAnchor.constraint(equalTo: self.stackView.widthAnchor) 92 | ] 93 | NSLayoutConstraint.activate(constraints) 94 | } 95 | 96 | private func createBoardRow(rowNumber: Int) -> UIStackView { 97 | let stackView = UIStackView() 98 | stackView.translatesAutoresizingMaskIntoConstraints = false 99 | stackView.axis = .horizontal 100 | stackView.alignment = .fill 101 | stackView.distribution = .fillEqually 102 | stackView.spacing = 10 103 | 104 | for index in 1 ... 3 { 105 | let button = UIButton() 106 | let id = String(index + ( (rowNumber - 1) * 3 ) ) 107 | button.restorationIdentifier = id 108 | button.backgroundColor = .lightGray 109 | button.titleLabel?.font = UIFont(name: "Helvetica", size: 50) 110 | button.addTarget(self, action: #selector(buttonPressed(_:)), for: .touchUpInside) 111 | 112 | self.buttons.append(button) 113 | stackView.addArrangedSubview(button) 114 | } 115 | 116 | return stackView 117 | } 118 | 119 | private func blockViewForUser() { 120 | DispatchQueue.main.async { 121 | self.resetButton.isHidden = true 122 | self.indicator.isHidden = false 123 | self.indicator.startAnimating() 124 | 125 | self.blockButtons() 126 | self.updateUI() 127 | } 128 | } 129 | 130 | private func unblockViewForUser() { 131 | DispatchQueue.main.async { 132 | self.unblockButtons() 133 | self.updateUI() 134 | 135 | self.resetButton.isHidden = false 136 | self.indicator.isHidden = true 137 | self.indicator.stopAnimating() 138 | } 139 | } 140 | 141 | @objc private func buttonPressed(_ sender: UIButton) { 142 | let position = buttonIDtoPosition(id: sender.restorationIdentifier!) 143 | 144 | DispatchQueue.global(qos: .userInteractive).async { 145 | self.gameModel.playerMakeMove(selectedPosition: position) 146 | 147 | self.blockViewForUser() 148 | 149 | self.gameModel.makeMinimaxMove() 150 | 151 | self.unblockViewForUser() 152 | } 153 | } 154 | 155 | private func setupResetButton() { 156 | self.resetButton = UIButton(type: .system) 157 | self.resetButton.translatesAutoresizingMaskIntoConstraints = false 158 | self.resetButton.setTitle("Reset", for: .normal) 159 | self.resetButton.backgroundColor = .lightGray 160 | self.resetButton.addTarget(self, action: #selector(resetButtonPressed(_:)), for: .touchUpInside) 161 | 162 | self.addSubview(self.resetButton) 163 | 164 | // constraints 165 | let constraints = [ 166 | self.resetButton.topAnchor.constraint(equalTo: self.stackView.bottomAnchor, constant: 10), 167 | self.resetButton.bottomAnchor.constraint(equalTo: self.bottomAnchor), 168 | self.resetButton.widthAnchor.constraint(equalTo: self.widthAnchor) 169 | ] 170 | NSLayoutConstraint.activate(constraints) 171 | } 172 | 173 | @objc private func resetButtonPressed(_ sender: UIButton) { 174 | self.gameModel.newRound() 175 | self.clearButtons() 176 | self.startGame() 177 | } 178 | 179 | private func setupIndicator() { 180 | self.indicator = UIActivityIndicatorView() 181 | self.indicator.translatesAutoresizingMaskIntoConstraints = false 182 | self.indicator.backgroundColor = .lightGray 183 | 184 | self.addSubview(self.indicator) 185 | 186 | // constraints 187 | let constraints = [ 188 | self.indicator.topAnchor.constraint(equalTo: self.stackView.bottomAnchor, constant: 10), 189 | self.indicator.bottomAnchor.constraint(equalTo: self.bottomAnchor), 190 | self.indicator.widthAnchor.constraint(equalTo: self.widthAnchor) 191 | ] 192 | NSLayoutConstraint.activate(constraints) 193 | } 194 | 195 | private func buttonIDtoPosition(id: String) -> Position { 196 | switch id { 197 | case "1": 198 | return Position(0, 0) 199 | case "2": 200 | return Position(0, 1) 201 | case "3": 202 | return Position(0, 2) 203 | case "4": 204 | return Position(1, 0) 205 | case "5": 206 | return Position(1, 1) 207 | case "6": 208 | return Position(1, 2) 209 | case "7": 210 | return Position(2, 0) 211 | case "8": 212 | return Position(2, 1) 213 | case "9": 214 | return Position(2, 2) 215 | default: 216 | return Position(0, 0) 217 | } 218 | } 219 | 220 | private func clearButtons() { 221 | for button in self.buttons { 222 | button.setTitle("", for: .normal) 223 | button.isUserInteractionEnabled = true 224 | } 225 | } 226 | 227 | private func unblockButtons() { 228 | for button in self.buttons { 229 | button.isUserInteractionEnabled = true 230 | } 231 | } 232 | 233 | private func blockButtons() { 234 | for button in self.buttons { 235 | button.isUserInteractionEnabled = false 236 | } 237 | } 238 | } 239 | -------------------------------------------------------------------------------- /algorithms/AI/minimax/Sources/Tests/Tests.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 50; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 9D029435268265690015843C /* BoardTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9D029434268265690015843C /* BoardTests.swift */; }; 11 | 9D02946D268285E20015843C /* PlayerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9D02946C268285E20015843C /* PlayerTests.swift */; }; 12 | 9D0294852682B1850015843C /* Minimax.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9D02947A2682B1840015843C /* Minimax.swift */; }; 13 | 9D0294862682B1850015843C /* PlayerSymbol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9D02947B2682B1840015843C /* PlayerSymbol.swift */; }; 14 | 9D0294872682B1850015843C /* Board.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9D02947D2682B1840015843C /* Board.swift */; }; 15 | 9D0294882682B1850015843C /* Player.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9D02947E2682B1840015843C /* Player.swift */; }; 16 | 9D0294892682B1850015843C /* BoardPosition.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9D02947F2682B1840015843C /* BoardPosition.swift */; }; 17 | 9D02948A2682B1850015843C /* PlayerType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9D0294802682B1840015843C /* PlayerType.swift */; }; 18 | 9D02948B2682B1850015843C /* GameModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9D0294812682B1840015843C /* GameModel.swift */; }; 19 | 9D02948C2682B1850015843C /* DifficultLevel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9D0294822682B1840015843C /* DifficultLevel.swift */; }; 20 | 9D02948D2682B1850015843C /* BoardStatus.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9D0294832682B1840015843C /* BoardStatus.swift */; }; 21 | 9D02948E2682B1850015843C /* GameStateValue.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9D0294842682B1850015843C /* GameStateValue.swift */; }; 22 | 9DB8564E268129FE0046878A /* MinimaxTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9DB8564D268129FE0046878A /* MinimaxTests.swift */; }; 23 | /* End PBXBuildFile section */ 24 | 25 | /* Begin PBXFileReference section */ 26 | 9D029434268265690015843C /* BoardTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BoardTests.swift; sourceTree = ""; }; 27 | 9D02946C268285E20015843C /* PlayerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlayerTests.swift; sourceTree = ""; }; 28 | 9D02947A2682B1840015843C /* Minimax.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Minimax.swift; path = ../Minimax.playground/Sources/Model/Minimax/Minimax.swift; sourceTree = ""; }; 29 | 9D02947B2682B1840015843C /* PlayerSymbol.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = PlayerSymbol.swift; path = ../Minimax.playground/Sources/Model/Player/PlayerSymbol.swift; sourceTree = ""; }; 30 | 9D02947D2682B1840015843C /* Board.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Board.swift; path = ../Minimax.playground/Sources/Model/Board/Board.swift; sourceTree = ""; }; 31 | 9D02947E2682B1840015843C /* Player.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Player.swift; path = ../Minimax.playground/Sources/Model/Player/Player.swift; sourceTree = ""; }; 32 | 9D02947F2682B1840015843C /* BoardPosition.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = BoardPosition.swift; path = ../Minimax.playground/Sources/Model/Board/BoardPosition.swift; sourceTree = ""; }; 33 | 9D0294802682B1840015843C /* PlayerType.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = PlayerType.swift; path = ../Minimax.playground/Sources/Model/Player/PlayerType.swift; sourceTree = ""; }; 34 | 9D0294812682B1840015843C /* GameModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = GameModel.swift; path = ../Minimax.playground/Sources/Model/GameModel/GameModel.swift; sourceTree = ""; }; 35 | 9D0294822682B1840015843C /* DifficultLevel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = DifficultLevel.swift; path = ../Minimax.playground/Sources/Model/GameModel/DifficultLevel.swift; sourceTree = ""; }; 36 | 9D0294832682B1840015843C /* BoardStatus.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = BoardStatus.swift; path = ../Minimax.playground/Sources/Model/Board/BoardStatus.swift; sourceTree = ""; }; 37 | 9D0294842682B1850015843C /* GameStateValue.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = GameStateValue.swift; path = ../Minimax.playground/Sources/Model/Minimax/GameStateValue.swift; sourceTree = ""; }; 38 | 9DB8564A268129FE0046878A /* Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = Tests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 39 | 9DB8564D268129FE0046878A /* MinimaxTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MinimaxTests.swift; sourceTree = ""; }; 40 | 9DB8564F268129FE0046878A /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 41 | /* End PBXFileReference section */ 42 | 43 | /* Begin PBXFrameworksBuildPhase section */ 44 | 9DB85647268129FE0046878A /* Frameworks */ = { 45 | isa = PBXFrameworksBuildPhase; 46 | buildActionMask = 2147483647; 47 | files = ( 48 | ); 49 | runOnlyForDeploymentPostprocessing = 0; 50 | }; 51 | /* End PBXFrameworksBuildPhase section */ 52 | 53 | /* Begin PBXGroup section */ 54 | 9DB8563F268129EF0046878A = { 55 | isa = PBXGroup; 56 | children = ( 57 | 9D02947D2682B1840015843C /* Board.swift */, 58 | 9D02947F2682B1840015843C /* BoardPosition.swift */, 59 | 9D0294832682B1840015843C /* BoardStatus.swift */, 60 | 9D0294822682B1840015843C /* DifficultLevel.swift */, 61 | 9D0294812682B1840015843C /* GameModel.swift */, 62 | 9D0294842682B1850015843C /* GameStateValue.swift */, 63 | 9D02947A2682B1840015843C /* Minimax.swift */, 64 | 9D02947E2682B1840015843C /* Player.swift */, 65 | 9D02947B2682B1840015843C /* PlayerSymbol.swift */, 66 | 9D0294802682B1840015843C /* PlayerType.swift */, 67 | 9DB8564C268129FE0046878A /* Tests */, 68 | 9DB8564B268129FE0046878A /* Products */, 69 | ); 70 | sourceTree = ""; 71 | }; 72 | 9DB8564B268129FE0046878A /* Products */ = { 73 | isa = PBXGroup; 74 | children = ( 75 | 9DB8564A268129FE0046878A /* Tests.xctest */, 76 | ); 77 | name = Products; 78 | sourceTree = ""; 79 | }; 80 | 9DB8564C268129FE0046878A /* Tests */ = { 81 | isa = PBXGroup; 82 | children = ( 83 | 9DB8564F268129FE0046878A /* Info.plist */, 84 | 9D02946C268285E20015843C /* PlayerTests.swift */, 85 | 9D029434268265690015843C /* BoardTests.swift */, 86 | 9DB8564D268129FE0046878A /* MinimaxTests.swift */, 87 | ); 88 | path = Tests; 89 | sourceTree = ""; 90 | }; 91 | /* End PBXGroup section */ 92 | 93 | /* Begin PBXNativeTarget section */ 94 | 9DB85649268129FE0046878A /* Tests */ = { 95 | isa = PBXNativeTarget; 96 | buildConfigurationList = 9DB85650268129FE0046878A /* Build configuration list for PBXNativeTarget "Tests" */; 97 | buildPhases = ( 98 | 9DB85646268129FE0046878A /* Sources */, 99 | 9DB85647268129FE0046878A /* Frameworks */, 100 | 9DB85648268129FE0046878A /* Resources */, 101 | ); 102 | buildRules = ( 103 | ); 104 | dependencies = ( 105 | ); 106 | name = Tests; 107 | productName = Tests; 108 | productReference = 9DB8564A268129FE0046878A /* Tests.xctest */; 109 | productType = "com.apple.product-type.bundle.unit-test"; 110 | }; 111 | /* End PBXNativeTarget section */ 112 | 113 | /* Begin PBXProject section */ 114 | 9DB85640268129EF0046878A /* Project object */ = { 115 | isa = PBXProject; 116 | attributes = { 117 | LastSwiftUpdateCheck = 1250; 118 | LastUpgradeCheck = 1250; 119 | TargetAttributes = { 120 | 9DB85649268129FE0046878A = { 121 | CreatedOnToolsVersion = 12.5; 122 | }; 123 | }; 124 | }; 125 | buildConfigurationList = 9DB85643268129EF0046878A /* Build configuration list for PBXProject "Tests" */; 126 | compatibilityVersion = "Xcode 9.3"; 127 | developmentRegion = en; 128 | hasScannedForEncodings = 0; 129 | knownRegions = ( 130 | en, 131 | Base, 132 | ); 133 | mainGroup = 9DB8563F268129EF0046878A; 134 | productRefGroup = 9DB8564B268129FE0046878A /* Products */; 135 | projectDirPath = ""; 136 | projectRoot = ""; 137 | targets = ( 138 | 9DB85649268129FE0046878A /* Tests */, 139 | ); 140 | }; 141 | /* End PBXProject section */ 142 | 143 | /* Begin PBXResourcesBuildPhase section */ 144 | 9DB85648268129FE0046878A /* Resources */ = { 145 | isa = PBXResourcesBuildPhase; 146 | buildActionMask = 2147483647; 147 | files = ( 148 | ); 149 | runOnlyForDeploymentPostprocessing = 0; 150 | }; 151 | /* End PBXResourcesBuildPhase section */ 152 | 153 | /* Begin PBXSourcesBuildPhase section */ 154 | 9DB85646268129FE0046878A /* Sources */ = { 155 | isa = PBXSourcesBuildPhase; 156 | buildActionMask = 2147483647; 157 | files = ( 158 | 9D029435268265690015843C /* BoardTests.swift in Sources */, 159 | 9D02948E2682B1850015843C /* GameStateValue.swift in Sources */, 160 | 9DB8564E268129FE0046878A /* MinimaxTests.swift in Sources */, 161 | 9D0294872682B1850015843C /* Board.swift in Sources */, 162 | 9D0294892682B1850015843C /* BoardPosition.swift in Sources */, 163 | 9D02948A2682B1850015843C /* PlayerType.swift in Sources */, 164 | 9D02948B2682B1850015843C /* GameModel.swift in Sources */, 165 | 9D02948C2682B1850015843C /* DifficultLevel.swift in Sources */, 166 | 9D0294862682B1850015843C /* PlayerSymbol.swift in Sources */, 167 | 9D02948D2682B1850015843C /* BoardStatus.swift in Sources */, 168 | 9D0294882682B1850015843C /* Player.swift in Sources */, 169 | 9D02946D268285E20015843C /* PlayerTests.swift in Sources */, 170 | 9D0294852682B1850015843C /* Minimax.swift in Sources */, 171 | ); 172 | runOnlyForDeploymentPostprocessing = 0; 173 | }; 174 | /* End PBXSourcesBuildPhase section */ 175 | 176 | /* Begin XCBuildConfiguration section */ 177 | 9DB85644268129EF0046878A /* Debug */ = { 178 | isa = XCBuildConfiguration; 179 | buildSettings = { 180 | }; 181 | name = Debug; 182 | }; 183 | 9DB85645268129EF0046878A /* Release */ = { 184 | isa = XCBuildConfiguration; 185 | buildSettings = { 186 | }; 187 | name = Release; 188 | }; 189 | 9DB85651268129FE0046878A /* Debug */ = { 190 | isa = XCBuildConfiguration; 191 | buildSettings = { 192 | ALWAYS_SEARCH_USER_PATHS = NO; 193 | CLANG_ANALYZER_NONNULL = YES; 194 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 195 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 196 | CLANG_CXX_LIBRARY = "libc++"; 197 | CLANG_ENABLE_MODULES = YES; 198 | CLANG_ENABLE_OBJC_ARC = YES; 199 | CLANG_ENABLE_OBJC_WEAK = YES; 200 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 201 | CLANG_WARN_BOOL_CONVERSION = YES; 202 | CLANG_WARN_COMMA = YES; 203 | CLANG_WARN_CONSTANT_CONVERSION = YES; 204 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 205 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 206 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 207 | CLANG_WARN_EMPTY_BODY = YES; 208 | CLANG_WARN_ENUM_CONVERSION = YES; 209 | CLANG_WARN_INFINITE_RECURSION = YES; 210 | CLANG_WARN_INT_CONVERSION = YES; 211 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 212 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 213 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 214 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 215 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 216 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 217 | CLANG_WARN_STRICT_PROTOTYPES = YES; 218 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 219 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 220 | CLANG_WARN_UNREACHABLE_CODE = YES; 221 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 222 | CODE_SIGN_STYLE = Automatic; 223 | COMBINE_HIDPI_IMAGES = YES; 224 | COPY_PHASE_STRIP = NO; 225 | DEBUG_INFORMATION_FORMAT = dwarf; 226 | ENABLE_STRICT_OBJC_MSGSEND = YES; 227 | ENABLE_TESTABILITY = YES; 228 | GCC_C_LANGUAGE_STANDARD = gnu11; 229 | GCC_DYNAMIC_NO_PIC = NO; 230 | GCC_NO_COMMON_BLOCKS = YES; 231 | GCC_OPTIMIZATION_LEVEL = 0; 232 | GCC_PREPROCESSOR_DEFINITIONS = ( 233 | "DEBUG=1", 234 | "$(inherited)", 235 | ); 236 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 237 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 238 | GCC_WARN_UNDECLARED_SELECTOR = YES; 239 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 240 | GCC_WARN_UNUSED_FUNCTION = YES; 241 | GCC_WARN_UNUSED_VARIABLE = YES; 242 | INFOPLIST_FILE = Tests/Info.plist; 243 | LD_RUNPATH_SEARCH_PATHS = ( 244 | "$(inherited)", 245 | "@executable_path/../Frameworks", 246 | "@loader_path/../Frameworks", 247 | ); 248 | MACOSX_DEPLOYMENT_TARGET = 11.3; 249 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; 250 | MTL_FAST_MATH = YES; 251 | ONLY_ACTIVE_ARCH = YES; 252 | PRODUCT_BUNDLE_IDENTIFIER = com.example.Tests; 253 | PRODUCT_NAME = "$(TARGET_NAME)"; 254 | SDKROOT = macosx; 255 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 256 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 257 | SWIFT_VERSION = 5.0; 258 | }; 259 | name = Debug; 260 | }; 261 | 9DB85652268129FE0046878A /* Release */ = { 262 | isa = XCBuildConfiguration; 263 | buildSettings = { 264 | ALWAYS_SEARCH_USER_PATHS = NO; 265 | CLANG_ANALYZER_NONNULL = YES; 266 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 267 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 268 | CLANG_CXX_LIBRARY = "libc++"; 269 | CLANG_ENABLE_MODULES = YES; 270 | CLANG_ENABLE_OBJC_ARC = YES; 271 | CLANG_ENABLE_OBJC_WEAK = YES; 272 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 273 | CLANG_WARN_BOOL_CONVERSION = YES; 274 | CLANG_WARN_COMMA = YES; 275 | CLANG_WARN_CONSTANT_CONVERSION = YES; 276 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 277 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 278 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 279 | CLANG_WARN_EMPTY_BODY = YES; 280 | CLANG_WARN_ENUM_CONVERSION = YES; 281 | CLANG_WARN_INFINITE_RECURSION = YES; 282 | CLANG_WARN_INT_CONVERSION = YES; 283 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 284 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 285 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 286 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 287 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 288 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 289 | CLANG_WARN_STRICT_PROTOTYPES = YES; 290 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 291 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 292 | CLANG_WARN_UNREACHABLE_CODE = YES; 293 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 294 | CODE_SIGN_STYLE = Automatic; 295 | COMBINE_HIDPI_IMAGES = YES; 296 | COPY_PHASE_STRIP = NO; 297 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 298 | ENABLE_NS_ASSERTIONS = NO; 299 | ENABLE_STRICT_OBJC_MSGSEND = YES; 300 | GCC_C_LANGUAGE_STANDARD = gnu11; 301 | GCC_NO_COMMON_BLOCKS = YES; 302 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 303 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 304 | GCC_WARN_UNDECLARED_SELECTOR = YES; 305 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 306 | GCC_WARN_UNUSED_FUNCTION = YES; 307 | GCC_WARN_UNUSED_VARIABLE = YES; 308 | INFOPLIST_FILE = Tests/Info.plist; 309 | LD_RUNPATH_SEARCH_PATHS = ( 310 | "$(inherited)", 311 | "@executable_path/../Frameworks", 312 | "@loader_path/../Frameworks", 313 | ); 314 | MACOSX_DEPLOYMENT_TARGET = 11.3; 315 | MTL_ENABLE_DEBUG_INFO = NO; 316 | MTL_FAST_MATH = YES; 317 | PRODUCT_BUNDLE_IDENTIFIER = com.example.Tests; 318 | PRODUCT_NAME = "$(TARGET_NAME)"; 319 | SDKROOT = macosx; 320 | SWIFT_COMPILATION_MODE = wholemodule; 321 | SWIFT_OPTIMIZATION_LEVEL = "-O"; 322 | SWIFT_VERSION = 5.0; 323 | }; 324 | name = Release; 325 | }; 326 | /* End XCBuildConfiguration section */ 327 | 328 | /* Begin XCConfigurationList section */ 329 | 9DB85643268129EF0046878A /* Build configuration list for PBXProject "Tests" */ = { 330 | isa = XCConfigurationList; 331 | buildConfigurations = ( 332 | 9DB85644268129EF0046878A /* Debug */, 333 | 9DB85645268129EF0046878A /* Release */, 334 | ); 335 | defaultConfigurationIsVisible = 0; 336 | defaultConfigurationName = Release; 337 | }; 338 | 9DB85650268129FE0046878A /* Build configuration list for PBXNativeTarget "Tests" */ = { 339 | isa = XCConfigurationList; 340 | buildConfigurations = ( 341 | 9DB85651268129FE0046878A /* Debug */, 342 | 9DB85652268129FE0046878A /* Release */, 343 | ); 344 | defaultConfigurationIsVisible = 0; 345 | defaultConfigurationName = Release; 346 | }; 347 | /* End XCConfigurationList section */ 348 | }; 349 | rootObject = 9DB85640268129EF0046878A /* Project object */; 350 | } 351 | --------------------------------------------------------------------------------