├── .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 |
--------------------------------------------------------------------------------