Repository: TheAlgorithms/Swift
Branch: master
Commit: 2c9eb8b85dee
Files: 57
Total size: 101.8 KB
Directory structure:
gitextract_yelu_m4v/
├── .github/
│ └── workflows/
│ ├── .stale.yml
│ └── directory_workflow.yml
├── .gitignore
├── DIRECTORY.md
├── README.md
├── Search/
│ ├── BinarySearch.swift
│ └── LinearSearch.swift
├── algorithms/
│ ├── AI/
│ │ └── minimax/
│ │ ├── README.md
│ │ └── Sources/
│ │ ├── Minimax.playground/
│ │ │ ├── Contents.swift
│ │ │ ├── Sources/
│ │ │ │ ├── Model/
│ │ │ │ │ ├── Board/
│ │ │ │ │ │ ├── Board.swift
│ │ │ │ │ │ ├── BoardPosition.swift
│ │ │ │ │ │ └── BoardStatus.swift
│ │ │ │ │ ├── GameModel/
│ │ │ │ │ │ ├── DifficultLevel.swift
│ │ │ │ │ │ └── GameModel.swift
│ │ │ │ │ ├── Minimax/
│ │ │ │ │ │ ├── GameStateValue.swift
│ │ │ │ │ │ └── Minimax.swift
│ │ │ │ │ └── Player/
│ │ │ │ │ ├── Player.swift
│ │ │ │ │ ├── PlayerSymbol.swift
│ │ │ │ │ └── PlayerType.swift
│ │ │ │ └── View/
│ │ │ │ └── BoardView.swift
│ │ │ ├── contents.xcplayground
│ │ │ └── playground.xcworkspace/
│ │ │ ├── contents.xcworkspacedata
│ │ │ └── xcshareddata/
│ │ │ └── WorkspaceSettings.xcsettings
│ │ └── Tests/
│ │ ├── Tests/
│ │ │ ├── BoardTests.swift
│ │ │ ├── Info.plist
│ │ │ ├── MinimaxTests.swift
│ │ │ └── PlayerTests.swift
│ │ └── Tests.xcodeproj/
│ │ ├── project.pbxproj
│ │ └── project.xcworkspace/
│ │ ├── contents.xcworkspacedata
│ │ └── xcshareddata/
│ │ ├── IDEWorkspaceChecks.plist
│ │ └── WorkspaceSettings.xcsettings
│ ├── conversion/
│ │ ├── binary-to-decimal.swift
│ │ └── decimal-to-binary.swift
│ ├── palindrome/
│ │ ├── palindrome_indices.swift
│ │ ├── palindrome_recursion.swift
│ │ └── palindrome_reversed.swift
│ └── parsing/
│ └── shunting_yard/
│ └── shunting_yard.swift
├── data_structures/
│ ├── Linked List/
│ │ └── LinkedList.swift
│ ├── Stack/
│ │ └── stack.swift
│ ├── doubly_linked_list/
│ │ └── DoublyLinkedList.swift
│ ├── heap/
│ │ └── heap.swift
│ ├── queue/
│ │ └── queue.swift
│ └── union_find/
│ └── union_find.swift
├── graph/
│ ├── BFS/
│ │ └── BFS.swift
│ ├── DFS/
│ │ └── DFS.swift
│ ├── Graph.swift
│ └── spanning_tree/
│ ├── dijkstra.swift
│ └── kruskal.swift
├── recursion/
│ └── fibonacci.swift
├── sorts/
│ ├── BubbleSort.swift
│ ├── CocktailSort.swift
│ ├── InsertionSort.swift
│ ├── MergeSort.swift
│ ├── PancakeSort.swift
│ ├── QuickSort.swift
│ └── SelectionSort.swift
└── trees/
└── tree.swift
================================================
FILE CONTENTS
================================================
================================================
FILE: .github/workflows/.stale.yml
================================================
# Configuration for probot-stale - https://github.com/probot/stale
# Number of days of inactivity before an Issue or Pull Request becomes stale
daysUntilStale: 30
# Number of days of inactivity before an Issue or Pull Request with the stale label is closed.
# Set to false to disable. If disabled, issues still need to be closed manually, but will remain marked as stale.
daysUntilClose: 7
# Only issues or pull requests with all of these labels are check if stale. Defaults to `[]` (disabled)
onlyLabels: []
# Issues or Pull Requests with these labels will never be considered stale. Set to `[]` to disable
exemptLabels:
- "Status: on hold"
# Set to true to ignore issues in a project (defaults to false)
exemptProjects: false
# Set to true to ignore issues in a milestone (defaults to false)
exemptMilestones: false
# Set to true to ignore issues with an assignee (defaults to false)
exemptAssignees: false
# Label to use when marking as stale
staleLabel: stale
# Comment to post when removing the stale label.
# unmarkComment: >
# Your comment here.
# Optionally, specify configuration settings that are specific to just 'issues' or 'pulls':
pulls:
# Comment to post when marking as stale. Set to `false` to disable
markComment: >
This pull request has been automatically marked as stale because it has not had
recent activity. It will be closed if no further activity occurs. Thank you
for your contributions.
# Comment to post when closing a stale Pull Request.
closeComment: >
Please reopen this pull request once you commit the changes requested
or make improvements on the code. If this is not the case and you need
some help, feel free to seek help from our [Gitter](https://gitter.im/TheAlgorithms)
or ping one of the reviewers. Thank you for your contributions!
issues:
# Comment to post when marking as stale. Set to `false` to disable
markComment: >
This issue has been automatically marked as stale because it has not had
recent activity. It will be closed if no further activity occurs. Thank you
for your contributions.
# Comment to post when closing a stale Issue.
closeComment: >
Please reopen this issue once you add more information and updates here.
If this is not the case and you need some help, feel free to seek help
from our [Gitter](https://gitter.im/TheAlgorithms) or ping one of the
reviewers. Thank you for your contributions!
================================================
FILE: .github/workflows/directory_workflow.yml
================================================
name: directory_md
on: [push, pull_request]
jobs:
MainSequence:
name: DIRECTORY.md
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1 # v2 is broken for git diff
- uses: actions/setup-python@v2
- name: Setup Git Specs
run: |
git config --global user.name github-actions
git config --global user.email '${GITHUB_ACTOR}@users.noreply.github.com'
git remote set-url origin https://x-access-token:${{ secrets.GITHUB_TOKEN }}@github.com/$GITHUB_REPOSITORY
- name: Update DIRECTORY.md
shell: python
run: |
import os
from typing import Iterator
URL_BASE = "https://github.com/TheAlgorithms/Swift/blob/master"
g_output = []
def good_filepaths(top_dir: str = ".") -> Iterator[str]:
fs_exts = tuple(".swift".split())
for dirpath, dirnames, filenames in os.walk(top_dir):
dirnames[:] = [d for d in dirnames if d[0] not in "._"]
for filename in filenames:
if os.path.splitext(filename)[1].lower() in fs_exts:
yield os.path.join(dirpath, filename).lstrip("./")
def md_prefix(i):
return f"{i * ' '}*" if i else "\n##"
def print_path(old_path: str, new_path: str) -> str:
global g_output
old_parts = old_path.split(os.sep)
for i, new_part in enumerate(new_path.split(os.sep)):
if i + 1 > len(old_parts) or old_parts[i] != new_part:
if new_part:
g_output.append(f"{md_prefix(i)} {new_part.replace('_', ' ').title()}")
return new_path
def build_directory_md(top_dir: str = ".") -> str:
global g_output
old_path = ""
for filepath in sorted(good_filepaths(), key=str.lower):
filepath, filename = os.path.split(filepath)
if filepath != old_path:
old_path = print_path(old_path, filepath)
indent = (filepath.count(os.sep) + 1) if filepath else 0
url = "/".join((URL_BASE, filepath, filename)).replace(" ", "%20")
filename = os.path.splitext(filename.replace("_", " ").title())[0]
g_output.append(f"{md_prefix(indent)} [{filename}]({url})")
return "# List of all files\n" + "\n".join(g_output)
with open("DIRECTORY.md", "w") as out_file:
out_file.write(build_directory_md(".") + "\n")
- name: Commit DIRECTORY.md
run: |
git commit -m "updating DIRECTORY.md" DIRECTORY.md || true
git diff DIRECTORY.md
git push --force origin HEAD:$GITHUB_REF || true
================================================
FILE: .gitignore
================================================
.DS_Store
================================================
FILE: DIRECTORY.md
================================================
# List of all files
## Algorithms
* Ai
* Minimax
* Sources
* Minimax.Playground
* [Contents](https://github.com/TheAlgorithms/Swift/blob/master/algorithms/AI/minimax/Sources/Minimax.playground/Contents.swift)
* Sources
* Model
* Board
* [Board](https://github.com/TheAlgorithms/Swift/blob/master/algorithms/AI/minimax/Sources/Minimax.playground/Sources/Model/Board/Board.swift)
* [Boardposition](https://github.com/TheAlgorithms/Swift/blob/master/algorithms/AI/minimax/Sources/Minimax.playground/Sources/Model/Board/BoardPosition.swift)
* [Boardstatus](https://github.com/TheAlgorithms/Swift/blob/master/algorithms/AI/minimax/Sources/Minimax.playground/Sources/Model/Board/BoardStatus.swift)
* Gamemodel
* [Difficultlevel](https://github.com/TheAlgorithms/Swift/blob/master/algorithms/AI/minimax/Sources/Minimax.playground/Sources/Model/GameModel/DifficultLevel.swift)
* [Gamemodel](https://github.com/TheAlgorithms/Swift/blob/master/algorithms/AI/minimax/Sources/Minimax.playground/Sources/Model/GameModel/GameModel.swift)
* Minimax
* [Gamestatevalue](https://github.com/TheAlgorithms/Swift/blob/master/algorithms/AI/minimax/Sources/Minimax.playground/Sources/Model/Minimax/GameStateValue.swift)
* [Minimax](https://github.com/TheAlgorithms/Swift/blob/master/algorithms/AI/minimax/Sources/Minimax.playground/Sources/Model/Minimax/Minimax.swift)
* Player
* [Player](https://github.com/TheAlgorithms/Swift/blob/master/algorithms/AI/minimax/Sources/Minimax.playground/Sources/Model/Player/Player.swift)
* [Playersymbol](https://github.com/TheAlgorithms/Swift/blob/master/algorithms/AI/minimax/Sources/Minimax.playground/Sources/Model/Player/PlayerSymbol.swift)
* [Playertype](https://github.com/TheAlgorithms/Swift/blob/master/algorithms/AI/minimax/Sources/Minimax.playground/Sources/Model/Player/PlayerType.swift)
* View
* [Boardview](https://github.com/TheAlgorithms/Swift/blob/master/algorithms/AI/minimax/Sources/Minimax.playground/Sources/View/BoardView.swift)
* Tests
* Tests
* [Boardtests](https://github.com/TheAlgorithms/Swift/blob/master/algorithms/AI/minimax/Sources/Tests/Tests/BoardTests.swift)
* [Minimaxtests](https://github.com/TheAlgorithms/Swift/blob/master/algorithms/AI/minimax/Sources/Tests/Tests/MinimaxTests.swift)
* [Playertests](https://github.com/TheAlgorithms/Swift/blob/master/algorithms/AI/minimax/Sources/Tests/Tests/PlayerTests.swift)
* Conversion
* [Binary-To-Decimal](https://github.com/TheAlgorithms/Swift/blob/master/algorithms/conversion/binary-to-decimal.swift)
* [Decimal-To-Binary](https://github.com/TheAlgorithms/Swift/blob/master/algorithms/conversion/decimal-to-binary.swift)
* Palindrome
* [Palindrome Indices](https://github.com/TheAlgorithms/Swift/blob/master/algorithms/palindrome/palindrome_indices.swift)
* [Palindrome Recursion](https://github.com/TheAlgorithms/Swift/blob/master/algorithms/palindrome/palindrome_recursion.swift)
* [Palindrome Reversed](https://github.com/TheAlgorithms/Swift/blob/master/algorithms/palindrome/palindrome_reversed.swift)
* Parsing
* Shunting Yard
* [Shunting Yard](https://github.com/TheAlgorithms/Swift/blob/master/algorithms/parsing/shunting_yard/shunting_yard.swift)
## Data Structures
* Doubly Linked List
* [Doublylinkedlist](https://github.com/TheAlgorithms/Swift/blob/master/data_structures/doubly_linked_list/DoublyLinkedList.swift)
* Heap
* [Heap](https://github.com/TheAlgorithms/Swift/blob/master/data_structures/heap/heap.swift)
* Linked List
* [Linkedlist](https://github.com/TheAlgorithms/Swift/blob/master/data_structures/Linked%20List/LinkedList.swift)
* Queue
* [Queue](https://github.com/TheAlgorithms/Swift/blob/master/data_structures/queue/queue.swift)
* Stack
* [Stack](https://github.com/TheAlgorithms/Swift/blob/master/data_structures/Stack/stack.swift)
* Union Find
* [Union Find](https://github.com/TheAlgorithms/Swift/blob/master/data_structures/union_find/union_find.swift)
## Graph
* Bfs
* [Bfs](https://github.com/TheAlgorithms/Swift/blob/master/graph/BFS/BFS.swift)
* Dfs
* [Dfs](https://github.com/TheAlgorithms/Swift/blob/master/graph/DFS/DFS.swift)
* [Graph](https://github.com/TheAlgorithms/Swift/blob/master/graph/Graph.swift)
* Spanning Tree
* [Dijkstra](https://github.com/TheAlgorithms/Swift/blob/master/graph/spanning_tree/dijkstra.swift)
* [Kruskal](https://github.com/TheAlgorithms/Swift/blob/master/graph/spanning_tree/kruskal.swift)
## Recursion
* [Fibonacci](https://github.com/TheAlgorithms/Swift/blob/master/recursion/fibonacci.swift)
## Search
* [Binarysearch](https://github.com/TheAlgorithms/Swift/blob/master/Search/BinarySearch.swift)
* [Linearsearch](https://github.com/TheAlgorithms/Swift/blob/master/Search/LinearSearch.swift)
## Sorts
* [Bubblesort](https://github.com/TheAlgorithms/Swift/blob/master/sorts/BubbleSort.swift)
* [Cocktailsort](https://github.com/TheAlgorithms/Swift/blob/master/sorts/CocktailSort.swift)
* [Insertionsort](https://github.com/TheAlgorithms/Swift/blob/master/sorts/InsertionSort.swift)
* [Mergesort](https://github.com/TheAlgorithms/Swift/blob/master/sorts/MergeSort.swift)
* [Pancakesort](https://github.com/TheAlgorithms/Swift/blob/master/sorts/PancakeSort.swift)
* [Quicksort](https://github.com/TheAlgorithms/Swift/blob/master/sorts/QuickSort.swift)
* [Selectionsort](https://github.com/TheAlgorithms/Swift/blob/master/sorts/SelectionSort.swift)
## Trees
* [Tree](https://github.com/TheAlgorithms/Swift/blob/master/trees/tree.swift)
================================================
FILE: README.md
================================================
# The Algorithms - Swift
### All algorithms implemented in Swift (for education)
These implementations are for learning purposes. They may be less efficient than the implementations in the Swift standard library.
## Community Channel
We're on [Gitter](https://gitter.im/TheAlgorithms)! Please join us.
## List of Algorithms
See our [directory](DIRECTORY.md).
================================================
FILE: Search/BinarySearch.swift
================================================
import Foundation
public func binarySearch<T: Comparable>(_ a: [T], key: T) -> Int? {
var lowerBound = 0
var upperBound = a.count
while lowerBound < upperBound {
let midIndex = lowerBound + (upperBound - lowerBound) / 2
if a[midIndex] == key {
return midIndex
} else if a[midIndex] < key {
lowerBound = midIndex + 1
} else {
upperBound = midIndex
}
}
return nil
}
// The code below can be used for testing
// var numbers = [7, 10, 13, 17, 19, 24, 29, 31, 32, 37, 41, 43, 47, 51, 53, 119, 163, 611, 627]
// if let searchIndex = binarySearch(numbers, key: 10) {
// print("Element found on index: \(searchIndex)")
// }
// else {
// print("Element not found")
// }
================================================
FILE: Search/LinearSearch.swift
================================================
import Foundation
func linearSearch<T: Equatable>(_ array: [T], _ object: T) -> Int? {
for (index, obj) in array.enumerated() where obj == object {
return index
}
return nil
}
// The code below can be used for testing
// var numbers = [10, 119, 13, 24, 53, 17, 31, 7, 19, 627, 47, 163, 37, 611, 29, 43, 51, 41, 32]
// if let searchIndex = linearSearch(numbers,31) {
// print("Element found on index: \(searchIndex)")
// }
// else {
// print("Element not found")
// }
================================================
FILE: algorithms/AI/minimax/README.md
================================================
# Minimax algorithm
<p align="center"> <img src="Resources/image1.jpg" {:height="50%" width="50%"} /> </p>
## Runtime environment
<img src="https://img.shields.io/badge/Swift-5.3-orange.svg?style=flat" />
<img src="https://img.shields.io/badge/Xcode-12.4-blue.svg?style=flat" />
<img src="https://img.shields.io/badge/MacOS-11.2.3-blue.svg?style=flat" />
## Table of contents
* [General info](#general-info)
* [Functionality](#functionality)
* [Pseudocode](#pseudocode)
* [Demo](#demo)
* [Sources](#sources)
## General info
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:
- `` -1 `` - if the minimizing player wins
- `` 0 `` - in case of a tie
- `` 1 `` - if the maximizing player wins
``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.
Parameters:
- ``searching depth`` - how many moves in depth is to be calculated by the algorithm
Input:
- ``actual board state`` - in the form of an array for players symbols (cross/circle)
- ``two player symbols`` - cross / circle
Output:
- ``the best move for autonomus(AI) player`` - Position(row: Int, column: Int)
## Functionality
- example of use in Swift Playground with interactive UIView
- unit tests in XCode
## Pseudocode
```
function alphabeta(node, depth, α, β, maximizingPlayer) is
if depth = 0 or node is a terminal node then
return the heuristic value of node
if maximizingPlayer then
value := −∞
for each child of node do
value := max(value, alphabeta(child, depth − 1, α, β, FALSE))
if value ≥ β then
break (* β cutoff *)
α := max(α, value)
return value
else
value := +∞
for each child of node do
value := min(value, alphabeta(child, depth − 1, α, β, TRUE))
if value ≤ α then
break (* α cutoff *)
β := min(β, value)
return value
```
## Demo
<p align="center"> <img src="Resources/demo.gif" {:height="100%" width="100%"} /> </p>
## Sources
* Minimax algorithm: https://en.wikipedia.org/wiki/Minimax
* Alpha-beta prunning: https://en.wikipedia.org/wiki/Alpha–beta_pruning
## Author
Written by Michał Nowak(mnowak061)
================================================
FILE: algorithms/AI/minimax/Sources/Minimax.playground/Contents.swift
================================================
import UIKit
import PlaygroundSupport
let boardSize = CGSize(width: 500, height: 550)
let boardView = BoardView(frame: CGRect(origin: .zero, size: boardSize))
PlaygroundPage.current.needsIndefiniteExecution = true
PlaygroundPage.current.liveView = boardView
================================================
FILE: algorithms/AI/minimax/Sources/Minimax.playground/Sources/Model/Board/Board.swift
================================================
public struct Board {
// MARK: -- Public variable's
public var size: Int
// MARK: -- Private variable's
private var table: [ [PlayerSymbol?] ]
// MARK: -- Public function's
public init(size: Int) {
self.size = size
self.table = []
self.clear()
}
public mutating func clear() {
self.table = Array(repeating: Array(repeating: PlayerSymbol.empty, count: size), count: size)
}
public func hasEmptyField() -> Bool {
for i in 0 ..< self.size {
for j in 0 ..< self.size {
if self.table[i][j] == PlayerSymbol.empty {
return true
}
}
}
return false
}
public func symbol(forPosition position: Position) -> PlayerSymbol? {
guard position.row < self.size, position.column < size else { return nil }
return self.table[position.row][position.column]
}
public mutating func makeMove(player: Player, position: Position) {
guard self.symbol(forPosition: position) == PlayerSymbol.empty else { return }
guard self.symbol(forPosition: position) != player.symbol else { return }
self.table[position.row][position.column] = player.symbol
}
public func check(player: Player) -> BoardStatus {
let playerSymbol: PlayerSymbol = player.symbol
if self.foundWinInRows(playerSymbol) { return BoardStatus.win }
if self.foundWinInColumns(playerSymbol) { return BoardStatus.win }
if self.foundWinInSlants(playerSymbol) { return BoardStatus.win }
if self.hasEmptyField() { return BoardStatus.continues } else { return BoardStatus.draw }
}
// MARK: -- Private function's
private func foundWinInRows(_ playerSymbol: PlayerSymbol) -> Bool {
for i in 0 ..< self.size {
var theSameSymbolsInRowCount = 0
for j in 0 ..< self.size - 1 {
if self.table[i][j] == self.table[i][j+1] && (self.table[i][j] == playerSymbol) {
theSameSymbolsInRowCount += 1
} else {
theSameSymbolsInRowCount = 0
}
}
if theSameSymbolsInRowCount == self.size - 1 {
return true
}
}
return false
}
private func foundWinInColumns(_ playerSymbol: PlayerSymbol) -> Bool {
for j in 0 ..< self.size {
var theSameSymbolsInColumnCount = 0
for i in 0 ..< self.size - 1 {
if self.table[i][j] == self.table[i+1][j] && (self.table[i][j] == playerSymbol) {
theSameSymbolsInColumnCount += 1
} else {
theSameSymbolsInColumnCount = 0
}
}
if theSameSymbolsInColumnCount == self.size - 1 {
return true
}
}
return false
}
private func foundWinInSlants(_ playerSymbol: PlayerSymbol) -> Bool {
var theSameSymbolsInSlantCount = 0
for i in 0 ..< self.size {
for j in -(self.size - 1) ... 0 {
if(self.table[-j][i] == playerSymbol) {
var k: Int = -j
var l: Int = i
theSameSymbolsInSlantCount = 0
while l < self.size && k >= 0 {
if self.table[k][l] == playerSymbol {
theSameSymbolsInSlantCount += 1
} else {
theSameSymbolsInSlantCount = 0
}
k -= 1
l += 1
if theSameSymbolsInSlantCount == self.size {
return true
}
}
theSameSymbolsInSlantCount = 0
}
theSameSymbolsInSlantCount = 0
}
theSameSymbolsInSlantCount = 0
}
theSameSymbolsInSlantCount = 0
for i in 0 ..< self.size {
for j in 0 ..< self.size {
if(self.table[j][i] == playerSymbol) {
var k: Int = j
var l: Int = i
theSameSymbolsInSlantCount = 0
while l < self.size && k < self.size {
if self.table[k][l] == playerSymbol {
theSameSymbolsInSlantCount += 1
} else {
theSameSymbolsInSlantCount = 0
}
k += 1
l += 1
if theSameSymbolsInSlantCount == self.size {
return true
}
}
theSameSymbolsInSlantCount = 0
}
theSameSymbolsInSlantCount = 0
}
theSameSymbolsInSlantCount = 0
}
return false
}
}
================================================
FILE: algorithms/AI/minimax/Sources/Minimax.playground/Sources/Model/Board/BoardPosition.swift
================================================
public typealias Position = (row: Int, column: Int)
================================================
FILE: algorithms/AI/minimax/Sources/Minimax.playground/Sources/Model/Board/BoardStatus.swift
================================================
public enum BoardStatus {
case continues
case win
case draw
}
================================================
FILE: algorithms/AI/minimax/Sources/Minimax.playground/Sources/Model/GameModel/DifficultLevel.swift
================================================
public enum DifficultLevel: Int {
case easy = 2
case medium = 3
case hard = 5
}
================================================
FILE: algorithms/AI/minimax/Sources/Minimax.playground/Sources/Model/GameModel/GameModel.swift
================================================
import Foundation
public class GameModel {
// MARK: -- Public variable's
public var board: Board!
public var gameStatus: BoardStatus
// MARK: -- Private variable's
private var playersList: [Player]!
private var movementsSequence: [Int]!
private var actualPlayerIndex: Int!
private var actualPlayer: Player {
get {
return playersList[actualPlayerIndex]
}
}
private var difficultLevel: DifficultLevel = DifficultLevel.hard
// MARK: -- Public function's
public init(boardSize: Int, playersList: [Player], difficultLevel: DifficultLevel) {
self.board = Board.init(size: boardSize)
self.playersList = playersList
self.difficultLevel = difficultLevel
self.gameStatus = BoardStatus.continues
self.generateMovementsSequence()
self.changeActualPlayer()
}
public func update() {
self.gameStatus = board.check(player: actualPlayer)
switch self.gameStatus {
case BoardStatus.continues:
changeActualPlayer()
case BoardStatus.draw:
changeActualPlayer()
default: break
}
}
public func playerMakeMove(selectedPosition: (row: Int, column: Int)) {
guard board.symbol(forPosition: selectedPosition) == PlayerSymbol.empty else { return }
guard board.hasEmptyField() == true else { return }
board.makeMove(player: actualPlayer, position: selectedPosition)
update()
}
public func makeMinimaxMove() {
guard actualPlayer.type == PlayerType.computer else { return }
guard board.hasEmptyField() == true else { return }
sleep(1)
let selectedPosition: Position = minimaxMove(board: board, player: playersList[0], opponent: playersList[1], depth: self.difficultLevel.rawValue)
board.makeMove(player: actualPlayer, position: selectedPosition)
update()
}
public func newRound() {
board.clear()
gameStatus = BoardStatus.continues
generateMovementsSequence()
changeActualPlayer()
}
// MARK: -- Private function's
private func generateMovementsSequence() {
self.movementsSequence = []
let playersCount = playersList.count
let movesCount = (board.size * board.size)
var move = Int.random(in: 0 ..< playersCount)
movementsSequence.append(move)
for _ in 0 ..< movesCount - 1 {
move += 1
movementsSequence.append(move % playersCount)
}
}
private func changeActualPlayer() {
if !movementsSequence.isEmpty {
actualPlayerIndex = movementsSequence.first!
movementsSequence.removeFirst()
}
}
}
================================================
FILE: algorithms/AI/minimax/Sources/Minimax.playground/Sources/Model/Minimax/GameStateValue.swift
================================================
public enum GameStateValue: Int {
case min = -1
case null = 0
case max = 1
}
================================================
FILE: algorithms/AI/minimax/Sources/Minimax.playground/Sources/Model/Minimax/Minimax.swift
================================================
public func minimaxMove(board: Board, player: Player, opponent: Player, depth: Int) -> Position {
var bestVal = GameStateValue.min
var bestMoves: [Position] = []
for i in 0 ..< board.size {
for j in 0 ..< board.size {
if board.symbol(forPosition: Position(i, j)) == PlayerSymbol.empty {
var tempBoard = board
let move = Position(i, j)
tempBoard.makeMove(player: opponent, position: (i, j))
let moveVal = minMax(board: tempBoard, player: opponent, opponent: player,
depth: depth,
alpha: GameStateValue.min.rawValue, beta: GameStateValue.max.rawValue,
maximizingPlayer: false)
if moveVal.rawValue > bestVal.rawValue {
bestVal = moveVal
bestMoves = []
bestMoves.append(move)
} else if moveVal == bestVal {
bestMoves.append(move)
}
}
}
}
return bestMoves[Int.random(in: 0 ..< bestMoves.count)]
}
public func minMax(board: Board, player: Player, opponent: Player, depth: Int, alpha: Int, beta: Int, maximizingPlayer: Bool) -> GameStateValue {
var alpha = alpha
var beta = beta
if let gameResult = evaluateGameState(board: board, player: player, opponent: opponent) {
guard depth != 0 && gameResult != GameStateValue.min && gameResult != GameStateValue.max && gameResult != GameStateValue.null else {
return gameResult
}
}
if maximizingPlayer {
var maxEval = GameStateValue.min
for i in 0 ..< board.size {
for j in 0 ..< board.size {
if board.symbol(forPosition: Position(i, j)) == PlayerSymbol.empty {
var tempBoard = board
tempBoard.makeMove(player: player, position: Position(i, j))
let eval = minMax(board: tempBoard, player: player, opponent: opponent, depth: depth - 1,
alpha: alpha, beta: beta,
maximizingPlayer: !maximizingPlayer)
maxEval = GameStateValue(rawValue: max(maxEval.rawValue, eval.rawValue))!
alpha = max(alpha, eval.rawValue)
if beta <= alpha { break }
}
}
}
return maxEval
} else {
var minEval = GameStateValue.max
for i in 0 ..< board.size {
for j in 0 ..< board.size {
if board.symbol(forPosition: Position(i, j)) == PlayerSymbol.empty {
var tempBoard = board
tempBoard.makeMove(player: opponent, position: (i, j))
let eval = minMax(board: tempBoard, player: player, opponent: opponent, depth: depth - 1,
alpha: alpha, beta: beta,
maximizingPlayer: !maximizingPlayer)
minEval = GameStateValue(rawValue: min(minEval.rawValue, eval.rawValue))!
beta = min(beta, eval.rawValue)
if beta <= alpha { break }
}
}
}
return minEval
}
}
public func evaluateGameState(board: Board, player: Player, opponent: Player) -> GameStateValue? {
if board.check(player: player) == BoardStatus.win {
return GameStateValue.max
} else if board.check(player: opponent) == BoardStatus.win {
return GameStateValue.min
} else if board.check(player: player) == BoardStatus.draw || board.check(player: opponent) == BoardStatus.draw {
return GameStateValue.null
}
return nil
}
================================================
FILE: algorithms/AI/minimax/Sources/Minimax.playground/Sources/Model/Player/Player.swift
================================================
public struct Player {
// MARK: -- Public variable's
public var type: PlayerType
public var symbol: PlayerSymbol
// MARK: -- Public function's
public init(type: PlayerType, symbol: PlayerSymbol) {
self.type = type
self.symbol = symbol
}
}
================================================
FILE: algorithms/AI/minimax/Sources/Minimax.playground/Sources/Model/Player/PlayerSymbol.swift
================================================
public enum PlayerSymbol: String {
case empty = ""
case circle = "⭕️"
case cross = "❌"
}
================================================
FILE: algorithms/AI/minimax/Sources/Minimax.playground/Sources/Model/Player/PlayerType.swift
================================================
public enum PlayerType {
case computer
case human
}
================================================
FILE: algorithms/AI/minimax/Sources/Minimax.playground/Sources/View/BoardView.swift
================================================
import UIKit
public class BoardView: UIView {
// MARK: -- Public
public var gameModel: GameModel!
public var players = [Player(type: .human, symbol: .circle),
Player(type: .computer, symbol: .cross)]
// MARK: -- Override's
public override init(frame: CGRect) {
super.init(frame: frame)
self.setupBoard()
self.setupResetButton()
self.setupIndicator()
self.startGame()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
}
// MARK: -- Private
private var buttons: [UIButton] = []
private var stackView: UIStackView!
private var resetButton: UIButton!
private var indicator: UIActivityIndicatorView!
private func startGame() {
self.gameModel = GameModel.init(boardSize: 3, playersList: self.players, difficultLevel: .hard)
DispatchQueue.global(qos: .userInteractive).async {
self.blockViewForUser()
self.gameModel.makeMinimaxMove()
self.unblockViewForUser()
}
}
private func updateUI() {
if gameModel.gameStatus != BoardStatus.continues {
self.resetButton.setTitle("New game", for: .normal)
blockButtons()
} else {
self.resetButton.setTitle("Reset", for: .normal)
}
boardToButtons()
}
private func boardToButtons() {
var buttonIndex = 0
for row in 0 ..< 3 {
for column in 0 ..< 3 {
let symbol = gameModel.board.symbol(forPosition: Position(row, column))
if symbol != PlayerSymbol.empty {
self.buttons[buttonIndex].setTitle(symbol?.rawValue, for: .normal)
self.buttons[buttonIndex].isUserInteractionEnabled = false
}
buttonIndex += 1
}
}
}
private func setupBoard() {
self.stackView = UIStackView()
self.stackView.translatesAutoresizingMaskIntoConstraints = false
self.stackView.axis = .vertical
self.stackView.alignment = .fill
self.stackView.distribution = .fillEqually
self.stackView.spacing = 10
self.addSubview(self.stackView)
for index in 1 ... 3 {
let boardRow = self.createBoardRow(rowNumber: index)
self.stackView.addArrangedSubview(boardRow)
}
// constraints
let constraints = [
self.stackView.topAnchor.constraint(equalTo: self.topAnchor, constant: 10),
self.stackView.centerXAnchor.constraint(equalTo: self.centerXAnchor),
self.stackView.widthAnchor.constraint(equalTo: self.widthAnchor, constant: -20),
self.stackView.heightAnchor.constraint(equalTo: self.stackView.widthAnchor)
]
NSLayoutConstraint.activate(constraints)
}
private func createBoardRow(rowNumber: Int) -> UIStackView {
let stackView = UIStackView()
stackView.translatesAutoresizingMaskIntoConstraints = false
stackView.axis = .horizontal
stackView.alignment = .fill
stackView.distribution = .fillEqually
stackView.spacing = 10
for index in 1 ... 3 {
let button = UIButton()
let id = String(index + ( (rowNumber - 1) * 3 ) )
button.restorationIdentifier = id
button.backgroundColor = .lightGray
button.titleLabel?.font = UIFont(name: "Helvetica", size: 50)
button.addTarget(self, action: #selector(buttonPressed(_:)), for: .touchUpInside)
self.buttons.append(button)
stackView.addArrangedSubview(button)
}
return stackView
}
private func blockViewForUser() {
DispatchQueue.main.async {
self.resetButton.isHidden = true
self.indicator.isHidden = false
self.indicator.startAnimating()
self.blockButtons()
self.updateUI()
}
}
private func unblockViewForUser() {
DispatchQueue.main.async {
self.unblockButtons()
self.updateUI()
self.resetButton.isHidden = false
self.indicator.isHidden = true
self.indicator.stopAnimating()
}
}
@objc private func buttonPressed(_ sender: UIButton) {
let position = buttonIDtoPosition(id: sender.restorationIdentifier!)
DispatchQueue.global(qos: .userInteractive).async {
self.gameModel.playerMakeMove(selectedPosition: position)
self.blockViewForUser()
self.gameModel.makeMinimaxMove()
self.unblockViewForUser()
}
}
private func setupResetButton() {
self.resetButton = UIButton(type: .system)
self.resetButton.translatesAutoresizingMaskIntoConstraints = false
self.resetButton.setTitle("Reset", for: .normal)
self.resetButton.backgroundColor = .lightGray
self.resetButton.addTarget(self, action: #selector(resetButtonPressed(_:)), for: .touchUpInside)
self.addSubview(self.resetButton)
// constraints
let constraints = [
self.resetButton.topAnchor.constraint(equalTo: self.stackView.bottomAnchor, constant: 10),
self.resetButton.bottomAnchor.constraint(equalTo: self.bottomAnchor),
self.resetButton.widthAnchor.constraint(equalTo: self.widthAnchor)
]
NSLayoutConstraint.activate(constraints)
}
@objc private func resetButtonPressed(_ sender: UIButton) {
self.gameModel.newRound()
self.clearButtons()
self.startGame()
}
private func setupIndicator() {
self.indicator = UIActivityIndicatorView()
self.indicator.translatesAutoresizingMaskIntoConstraints = false
self.indicator.backgroundColor = .lightGray
self.addSubview(self.indicator)
// constraints
let constraints = [
self.indicator.topAnchor.constraint(equalTo: self.stackView.bottomAnchor, constant: 10),
self.indicator.bottomAnchor.constraint(equalTo: self.bottomAnchor),
self.indicator.widthAnchor.constraint(equalTo: self.widthAnchor)
]
NSLayoutConstraint.activate(constraints)
}
private func buttonIDtoPosition(id: String) -> Position {
switch id {
case "1":
return Position(0, 0)
case "2":
return Position(0, 1)
case "3":
return Position(0, 2)
case "4":
return Position(1, 0)
case "5":
return Position(1, 1)
case "6":
return Position(1, 2)
case "7":
return Position(2, 0)
case "8":
return Position(2, 1)
case "9":
return Position(2, 2)
default:
return Position(0, 0)
}
}
private func clearButtons() {
for button in self.buttons {
button.setTitle("", for: .normal)
button.isUserInteractionEnabled = true
}
}
private func unblockButtons() {
for button in self.buttons {
button.isUserInteractionEnabled = true
}
}
private func blockButtons() {
for button in self.buttons {
button.isUserInteractionEnabled = false
}
}
}
================================================
FILE: algorithms/AI/minimax/Sources/Minimax.playground/contents.xcplayground
================================================
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<playground version='5.0' target-platform='ios' buildActiveScheme='true' importAppTypes='true'>
<timeline fileName='timeline.xctimeline'/>
</playground>
================================================
FILE: algorithms/AI/minimax/Sources/Minimax.playground/playground.xcworkspace/contents.xcworkspacedata
================================================
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "group:">
</FileRef>
</Workspace>
================================================
FILE: algorithms/AI/minimax/Sources/Minimax.playground/playground.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings
================================================
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>IDEWorkspaceSharedSettings_AutocreateContextsIfNeeded</key>
<false/>
</dict>
</plist>
================================================
FILE: algorithms/AI/minimax/Sources/Tests/Tests/BoardTests.swift
================================================
import XCTest
class BoardTests: XCTestCase {
private var sut: Board!
private var boardSize = 3
override func setUp() {
super.setUp()
sut = Board(size: boardSize)
}
override func tearDown() {
sut = nil
super.tearDown()
}
func testInit() {
XCTAssertEqual(sut.size, boardSize)
XCTAssertEqual(allFieldsAreEmpty(), true)
}
func testSymbolForPosition() {
let player = Player(type: .human, symbol: .circle)
let position = Position(0, 0)
sut.clear()
XCTAssertEqual(sut.symbol(forPosition: position), PlayerSymbol.empty)
sut.makeMove(player: player, position: position)
XCTAssertEqual(sut.symbol(forPosition: position), player.symbol)
}
func testClear() {
let player = Player(type: .computer, symbol: .circle)
let position = Position(0, 0)
sut.makeMove(player: player, position: position)
XCTAssertEqual(allFieldsAreEmpty(), false)
sut.clear()
XCTAssertEqual(allFieldsAreEmpty(), true)
}
func testHasEmptyField() {
let player = Player(type: .computer, symbol: .circle)
sut.clear()
XCTAssertEqual(sut.hasEmptyField(), true)
sut.makeMove(player: player, position: Position(0, 0))
sut.makeMove(player: player, position: Position(0, 1))
sut.makeMove(player: player, position: Position(0, 2))
sut.makeMove(player: player, position: Position(1, 0))
sut.makeMove(player: player, position: Position(1, 1))
sut.makeMove(player: player, position: Position(1, 2))
sut.makeMove(player: player, position: Position(2, 0))
sut.makeMove(player: player, position: Position(2, 1))
sut.makeMove(player: player, position: Position(2, 2))
XCTAssertEqual(sut.hasEmptyField(), false)
}
func testMakeMove() {
let firstPlayer = Player(type: .human, symbol: .circle)
let secondPlayer = Player(type: .human, symbol: .cross)
let position = Position(0, 0)
sut.clear()
sut.makeMove(player: firstPlayer, position: position)
sut.makeMove(player: secondPlayer, position: position)
XCTAssertEqual(sut.symbol(forPosition: position), firstPlayer.symbol)
}
func testCheck() {
let firstPlayer = Player(type: .computer, symbol: .circle)
let secondPlayer = Player(type: .computer, symbol: .cross)
sut.clear()
XCTAssertEqual(sut.check(player: firstPlayer), BoardStatus.continues)
XCTAssertEqual(sut.check(player: secondPlayer), BoardStatus.continues)
sut.clear()
sut.makeMove(player: firstPlayer, position: Position(0, 0))
sut.makeMove(player: firstPlayer, position: Position(0, 1))
sut.makeMove(player: firstPlayer, position: Position(0, 2))
XCTAssertEqual(sut.check(player: firstPlayer), BoardStatus.win)
XCTAssertEqual(sut.check(player: secondPlayer), BoardStatus.continues)
sut.clear()
sut.makeMove(player: firstPlayer, position: Position(0, 0))
sut.makeMove(player: firstPlayer, position: Position(1, 0))
sut.makeMove(player: firstPlayer, position: Position(2, 0))
XCTAssertEqual(sut.check(player: firstPlayer), BoardStatus.win)
XCTAssertEqual(sut.check(player: secondPlayer), BoardStatus.continues)
sut.clear()
sut.makeMove(player: firstPlayer, position: Position(0, 0))
sut.makeMove(player: firstPlayer, position: Position(1, 1))
sut.makeMove(player: firstPlayer, position: Position(2, 2))
XCTAssertEqual(sut.check(player: firstPlayer), BoardStatus.win)
XCTAssertEqual(sut.check(player: secondPlayer), BoardStatus.continues)
sut.clear()
sut.makeMove(player: firstPlayer, position: Position(0, 0))
sut.makeMove(player: secondPlayer, position: Position(0, 1))
sut.makeMove(player: secondPlayer, position: Position(0, 2))
sut.makeMove(player: secondPlayer, position: Position(1, 0))
sut.makeMove(player: firstPlayer, position: Position(1, 1))
sut.makeMove(player: firstPlayer, position: Position(1, 2))
sut.makeMove(player: secondPlayer, position: Position(2, 0))
sut.makeMove(player: firstPlayer, position: Position(2, 1))
sut.makeMove(player: secondPlayer, position: Position(2, 2))
XCTAssertEqual(sut.check(player: firstPlayer), BoardStatus.draw)
XCTAssertEqual(sut.check(player: secondPlayer), BoardStatus.draw)
}
private func allFieldsAreEmpty() -> Bool {
var allFieldAreEmpty = true
for row in 0 ..< sut.size {
for column in 0 ..< sut.size {
if sut.symbol(forPosition: Position(row, column)) != PlayerSymbol.empty {
allFieldAreEmpty = false
}
}
}
return allFieldAreEmpty
}
}
================================================
FILE: algorithms/AI/minimax/Sources/Tests/Tests/Info.plist
================================================
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleVersion</key>
<string>1</string>
</dict>
</plist>
================================================
FILE: algorithms/AI/minimax/Sources/Tests/Tests/MinimaxTests.swift
================================================
import XCTest
class MinimaxTests: XCTestCase {
override func setUp() {
super.setUp()
}
override func tearDown() {
super.tearDown()
}
func testEvaluateGameState() {
var board = Board(size: 3)
let firstPlayer = Player(type: .human, symbol: .cross)
let secondPlayer = Player(type: .human, symbol: .circle)
board.clear()
XCTAssertEqual(evaluateGameState(board: board, player: firstPlayer, opponent: secondPlayer), nil)
board.makeMove(player: firstPlayer, position: Position(0, 0))
XCTAssertEqual(evaluateGameState(board: board, player: firstPlayer, opponent: secondPlayer), nil)
board.makeMove(player: firstPlayer, position: Position(0, 1))
board.makeMove(player: firstPlayer, position: Position(0, 2))
XCTAssertEqual(evaluateGameState(board: board, player: firstPlayer, opponent: secondPlayer), .max)
XCTAssertEqual(evaluateGameState(board: board, player: secondPlayer, opponent: firstPlayer), .min)
board.clear()
board.makeMove(player: secondPlayer, position: Position(0, 0))
board.makeMove(player: secondPlayer, position: Position(0, 1))
board.makeMove(player: secondPlayer, position: Position(0, 2))
board.makeMove(player: firstPlayer, position: Position(1, 0))
XCTAssertEqual(evaluateGameState(board: board, player: firstPlayer, opponent: secondPlayer), .min)
XCTAssertEqual(evaluateGameState(board: board, player: secondPlayer, opponent: firstPlayer), .max)
board.clear()
board.makeMove(player: firstPlayer, position: Position(0, 0))
board.makeMove(player: secondPlayer, position: Position(0, 1))
board.makeMove(player: secondPlayer, position: Position(0, 2))
board.makeMove(player: secondPlayer, position: Position(1, 0))
board.makeMove(player: firstPlayer, position: Position(1, 1))
board.makeMove(player: firstPlayer, position: Position(1, 2))
board.makeMove(player: secondPlayer, position: Position(2, 0))
board.makeMove(player: firstPlayer, position: Position(2, 1))
board.makeMove(player: secondPlayer, position: Position(2, 2))
XCTAssertEqual(evaluateGameState(board: board, player: firstPlayer, opponent: secondPlayer), .null)
XCTAssertEqual(evaluateGameState(board: board, player: secondPlayer, opponent: firstPlayer), .null)
}
}
================================================
FILE: algorithms/AI/minimax/Sources/Tests/Tests/PlayerTests.swift
================================================
import XCTest
class PlayerTests: XCTestCase {
private var sut: Player!
private var playerType: PlayerType = .human
private var playerSymbol: PlayerSymbol = .circle
override func setUp() {
super.setUp()
sut = Player(type: playerType, symbol: playerSymbol)
}
override func tearDown() {
sut = nil
super.tearDown()
}
func testInit() {
XCTAssertEqual(sut.type, playerType)
XCTAssertEqual(sut.symbol, playerSymbol)
}
}
================================================
FILE: algorithms/AI/minimax/Sources/Tests/Tests.xcodeproj/project.pbxproj
================================================
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 50;
objects = {
/* Begin PBXBuildFile section */
9D029435268265690015843C /* BoardTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9D029434268265690015843C /* BoardTests.swift */; };
9D02946D268285E20015843C /* PlayerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9D02946C268285E20015843C /* PlayerTests.swift */; };
9D0294852682B1850015843C /* Minimax.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9D02947A2682B1840015843C /* Minimax.swift */; };
9D0294862682B1850015843C /* PlayerSymbol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9D02947B2682B1840015843C /* PlayerSymbol.swift */; };
9D0294872682B1850015843C /* Board.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9D02947D2682B1840015843C /* Board.swift */; };
9D0294882682B1850015843C /* Player.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9D02947E2682B1840015843C /* Player.swift */; };
9D0294892682B1850015843C /* BoardPosition.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9D02947F2682B1840015843C /* BoardPosition.swift */; };
9D02948A2682B1850015843C /* PlayerType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9D0294802682B1840015843C /* PlayerType.swift */; };
9D02948B2682B1850015843C /* GameModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9D0294812682B1840015843C /* GameModel.swift */; };
9D02948C2682B1850015843C /* DifficultLevel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9D0294822682B1840015843C /* DifficultLevel.swift */; };
9D02948D2682B1850015843C /* BoardStatus.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9D0294832682B1840015843C /* BoardStatus.swift */; };
9D02948E2682B1850015843C /* GameStateValue.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9D0294842682B1850015843C /* GameStateValue.swift */; };
9DB8564E268129FE0046878A /* MinimaxTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9DB8564D268129FE0046878A /* MinimaxTests.swift */; };
/* End PBXBuildFile section */
/* Begin PBXFileReference section */
9D029434268265690015843C /* BoardTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BoardTests.swift; sourceTree = "<group>"; };
9D02946C268285E20015843C /* PlayerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlayerTests.swift; sourceTree = "<group>"; };
9D02947A2682B1840015843C /* Minimax.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Minimax.swift; path = ../Minimax.playground/Sources/Model/Minimax/Minimax.swift; sourceTree = "<group>"; };
9D02947B2682B1840015843C /* PlayerSymbol.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = PlayerSymbol.swift; path = ../Minimax.playground/Sources/Model/Player/PlayerSymbol.swift; sourceTree = "<group>"; };
9D02947D2682B1840015843C /* Board.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Board.swift; path = ../Minimax.playground/Sources/Model/Board/Board.swift; sourceTree = "<group>"; };
9D02947E2682B1840015843C /* Player.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Player.swift; path = ../Minimax.playground/Sources/Model/Player/Player.swift; sourceTree = "<group>"; };
9D02947F2682B1840015843C /* BoardPosition.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = BoardPosition.swift; path = ../Minimax.playground/Sources/Model/Board/BoardPosition.swift; sourceTree = "<group>"; };
9D0294802682B1840015843C /* PlayerType.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = PlayerType.swift; path = ../Minimax.playground/Sources/Model/Player/PlayerType.swift; sourceTree = "<group>"; };
9D0294812682B1840015843C /* GameModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = GameModel.swift; path = ../Minimax.playground/Sources/Model/GameModel/GameModel.swift; sourceTree = "<group>"; };
9D0294822682B1840015843C /* DifficultLevel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = DifficultLevel.swift; path = ../Minimax.playground/Sources/Model/GameModel/DifficultLevel.swift; sourceTree = "<group>"; };
9D0294832682B1840015843C /* BoardStatus.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = BoardStatus.swift; path = ../Minimax.playground/Sources/Model/Board/BoardStatus.swift; sourceTree = "<group>"; };
9D0294842682B1850015843C /* GameStateValue.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = GameStateValue.swift; path = ../Minimax.playground/Sources/Model/Minimax/GameStateValue.swift; sourceTree = "<group>"; };
9DB8564A268129FE0046878A /* Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = Tests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
9DB8564D268129FE0046878A /* MinimaxTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MinimaxTests.swift; sourceTree = "<group>"; };
9DB8564F268129FE0046878A /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
9DB85647268129FE0046878A /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
9DB8563F268129EF0046878A = {
isa = PBXGroup;
children = (
9D02947D2682B1840015843C /* Board.swift */,
9D02947F2682B1840015843C /* BoardPosition.swift */,
9D0294832682B1840015843C /* BoardStatus.swift */,
9D0294822682B1840015843C /* DifficultLevel.swift */,
9D0294812682B1840015843C /* GameModel.swift */,
9D0294842682B1850015843C /* GameStateValue.swift */,
9D02947A2682B1840015843C /* Minimax.swift */,
9D02947E2682B1840015843C /* Player.swift */,
9D02947B2682B1840015843C /* PlayerSymbol.swift */,
9D0294802682B1840015843C /* PlayerType.swift */,
9DB8564C268129FE0046878A /* Tests */,
9DB8564B268129FE0046878A /* Products */,
);
sourceTree = "<group>";
};
9DB8564B268129FE0046878A /* Products */ = {
isa = PBXGroup;
children = (
9DB8564A268129FE0046878A /* Tests.xctest */,
);
name = Products;
sourceTree = "<group>";
};
9DB8564C268129FE0046878A /* Tests */ = {
isa = PBXGroup;
children = (
9DB8564F268129FE0046878A /* Info.plist */,
9D02946C268285E20015843C /* PlayerTests.swift */,
9D029434268265690015843C /* BoardTests.swift */,
9DB8564D268129FE0046878A /* MinimaxTests.swift */,
);
path = Tests;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
9DB85649268129FE0046878A /* Tests */ = {
isa = PBXNativeTarget;
buildConfigurationList = 9DB85650268129FE0046878A /* Build configuration list for PBXNativeTarget "Tests" */;
buildPhases = (
9DB85646268129FE0046878A /* Sources */,
9DB85647268129FE0046878A /* Frameworks */,
9DB85648268129FE0046878A /* Resources */,
);
buildRules = (
);
dependencies = (
);
name = Tests;
productName = Tests;
productReference = 9DB8564A268129FE0046878A /* Tests.xctest */;
productType = "com.apple.product-type.bundle.unit-test";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
9DB85640268129EF0046878A /* Project object */ = {
isa = PBXProject;
attributes = {
LastSwiftUpdateCheck = 1250;
LastUpgradeCheck = 1250;
TargetAttributes = {
9DB85649268129FE0046878A = {
CreatedOnToolsVersion = 12.5;
};
};
};
buildConfigurationList = 9DB85643268129EF0046878A /* Build configuration list for PBXProject "Tests" */;
compatibilityVersion = "Xcode 9.3";
developmentRegion = en;
hasScannedForEncodings = 0;
knownRegions = (
en,
Base,
);
mainGroup = 9DB8563F268129EF0046878A;
productRefGroup = 9DB8564B268129FE0046878A /* Products */;
projectDirPath = "";
projectRoot = "";
targets = (
9DB85649268129FE0046878A /* Tests */,
);
};
/* End PBXProject section */
/* Begin PBXResourcesBuildPhase section */
9DB85648268129FE0046878A /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
9DB85646268129FE0046878A /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
9D029435268265690015843C /* BoardTests.swift in Sources */,
9D02948E2682B1850015843C /* GameStateValue.swift in Sources */,
9DB8564E268129FE0046878A /* MinimaxTests.swift in Sources */,
9D0294872682B1850015843C /* Board.swift in Sources */,
9D0294892682B1850015843C /* BoardPosition.swift in Sources */,
9D02948A2682B1850015843C /* PlayerType.swift in Sources */,
9D02948B2682B1850015843C /* GameModel.swift in Sources */,
9D02948C2682B1850015843C /* DifficultLevel.swift in Sources */,
9D0294862682B1850015843C /* PlayerSymbol.swift in Sources */,
9D02948D2682B1850015843C /* BoardStatus.swift in Sources */,
9D0294882682B1850015843C /* Player.swift in Sources */,
9D02946D268285E20015843C /* PlayerTests.swift in Sources */,
9D0294852682B1850015843C /* Minimax.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin XCBuildConfiguration section */
9DB85644268129EF0046878A /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
};
name = Debug;
};
9DB85645268129EF0046878A /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
};
name = Release;
};
9DB85651268129FE0046878A /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_ENABLE_OBJC_WEAK = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = dwarf;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
GCC_C_LANGUAGE_STANDARD = gnu11;
GCC_DYNAMIC_NO_PIC = NO;
GCC_NO_COMMON_BLOCKS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
INFOPLIST_FILE = Tests/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/../Frameworks",
"@loader_path/../Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 11.3;
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES;
ONLY_ACTIVE_ARCH = YES;
PRODUCT_BUNDLE_IDENTIFIER = com.example.Tests;
PRODUCT_NAME = "$(TARGET_NAME)";
SDKROOT = macosx;
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 5.0;
};
name = Debug;
};
9DB85652268129FE0046878A /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_ENABLE_OBJC_WEAK = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu11;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
INFOPLIST_FILE = Tests/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/../Frameworks",
"@loader_path/../Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 11.3;
MTL_ENABLE_DEBUG_INFO = NO;
MTL_FAST_MATH = YES;
PRODUCT_BUNDLE_IDENTIFIER = com.example.Tests;
PRODUCT_NAME = "$(TARGET_NAME)";
SDKROOT = macosx;
SWIFT_COMPILATION_MODE = wholemodule;
SWIFT_OPTIMIZATION_LEVEL = "-O";
SWIFT_VERSION = 5.0;
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
9DB85643268129EF0046878A /* Build configuration list for PBXProject "Tests" */ = {
isa = XCConfigurationList;
buildConfigurations = (
9DB85644268129EF0046878A /* Debug */,
9DB85645268129EF0046878A /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
9DB85650268129FE0046878A /* Build configuration list for PBXNativeTarget "Tests" */ = {
isa = XCConfigurationList;
buildConfigurations = (
9DB85651268129FE0046878A /* Debug */,
9DB85652268129FE0046878A /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
rootObject = 9DB85640268129EF0046878A /* Project object */;
}
================================================
FILE: algorithms/AI/minimax/Sources/Tests/Tests.xcodeproj/project.xcworkspace/contents.xcworkspacedata
================================================
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "self:">
</FileRef>
</Workspace>
================================================
FILE: algorithms/AI/minimax/Sources/Tests/Tests.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
================================================
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>IDEDidComputeMac32BitWarning</key>
<true/>
</dict>
</plist>
================================================
FILE: algorithms/AI/minimax/Sources/Tests/Tests.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings
================================================
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>IDEWorkspaceSharedSettings_AutocreateContextsIfNeeded</key>
<false/>
</dict>
</plist>
================================================
FILE: algorithms/conversion/binary-to-decimal.swift
================================================
import Foundation
/// This function accepts a binary number as String and converts it to decimal as Int.
/// If it's not valid binary number (a.k.a not made only from digits), it returns nil.
public func convertBinaryToDecimal(binary: String) -> Int? {
if let _ = Int(binary) {
var decimal = 0
let digits = binary.map { Int(String($0))! }.reversed()
print(digits)
var power = 1
for digit in digits {
decimal += digit * power
power *= 2
}
return decimal
}
return nil
}
================================================
FILE: algorithms/conversion/decimal-to-binary.swift
================================================
/// This function accepts a non-negative number and returns its binary form as String.
public func convertDecimalToBinary(decimal: Int) -> String {
var binary = ""
var decimal = decimal
while decimal != 0 {
binary.insert(decimal % 2 == 0 ? "0" : "1", at: binary.startIndex)
decimal /= 2
}
return binary
}
================================================
FILE: algorithms/palindrome/palindrome_indices.swift
================================================
// A palindrome is a string that reads the same forwards and backwards.
//
// Examples: "level", "radar", "madam", "A man, a plan, a canal: Panama".
extension String {
/// Iteratively comparing characters from the beginning and end of the string. Only include letters and numbers.
/// - Complexity: O(n), without allocating new space.
func isPalindrome() -> Bool {
var leftIndex = startIndex
var rightIndex = index(before: endIndex)
while leftIndex < rightIndex {
guard self[leftIndex].isLetter || self[leftIndex].isNumber else {
leftIndex = index(after: leftIndex)
continue
}
guard self[rightIndex].isLetter || self[rightIndex].isNumber else {
rightIndex = index(before: rightIndex)
continue
}
guard self[leftIndex].lowercased() == self[rightIndex].lowercased() else {
return false
}
leftIndex = index(after: leftIndex)
rightIndex = index(before: rightIndex)
}
return true
}
}
================================================
FILE: algorithms/palindrome/palindrome_recursion.swift
================================================
// A palindrome is a string that reads the same forwards and backwards.
//
// Examples: "level", "radar", "madam", "A man, a plan, a canal: Panama".
extension String {
/// Recursively comparing characters from the beginning and end of the string. Only include letters and numbers.
/// - Complexity: O(n), without allocating new space.
func isPalindrome() -> Bool {
isPalindromeRecursion(
leftIndex: startIndex,
rightIndex: index(before: endIndex)
)
}
private func isPalindromeRecursion(
leftIndex: String.Index,
rightIndex: String.Index
) -> Bool {
guard leftIndex < rightIndex else {
return true
}
guard self[leftIndex].isLetter || self[leftIndex].isNumber else {
return isPalindromeRecursion(
leftIndex: index(after: leftIndex),
rightIndex: rightIndex
)
}
guard self[rightIndex].isLetter || self[rightIndex].isNumber else {
return isPalindromeRecursion(
leftIndex: leftIndex,
rightIndex: index(before: rightIndex)
)
}
guard self[leftIndex].lowercased() == self[rightIndex].lowercased() else {
return false
}
return isPalindromeRecursion(
leftIndex: index(after: leftIndex),
rightIndex: index(before: rightIndex)
)
}
}
================================================
FILE: algorithms/palindrome/palindrome_reversed.swift
================================================
// A palindrome is a string that reads the same forwards and backwards.
//
// Examples: "level", "radar", "madam", "A man, a plan, a canal: Panama".
extension String {
/// Using the `reverse()` method to reverse the string and comparing it with the original. Only include letters and numbers.
/// - Complexity: O(n), with allocating O(n) space.
func isPalindrome() -> Bool {
let input = lowercased().filter { $0.isLetter || $0.isNumber }
return input == String(input.reversed())
}
}
================================================
FILE: algorithms/parsing/shunting_yard/shunting_yard.swift
================================================
import Foundation
enum ShuntingYard {
enum Operator: String, CaseIterable {
case power = "^"
case plus = "+"
case minus = "-"
case times = "*"
case divide = "/"
}
static func evaluate(_ string: String) -> Double {
let scanner = Scanner(string: string)
var numberStack: [Double] = []
var operatorStack: [Operator] = []
func applyOperator(_ op: Operator) {
guard let a = numberStack.popLast(), let b = numberStack.popLast() else {
return
}
numberStack.append(op.apply(a, b))
}
while !scanner.isAtEnd {
if let op = scanner.scanOperator() {
while let last = operatorStack.last, last.precedence > op.precedence || (op.leftAssociative && last.precedence == op.precedence) {
applyOperator(last)
operatorStack.removeLast()
}
operatorStack.append(op)
} else if let number = scanner.scanDouble() {
numberStack.append(number)
} else {
break
}
}
while let op = operatorStack.popLast() {
applyOperator(op)
}
return numberStack.first ?? 0
}
}
extension ShuntingYard.Operator {
var precedence: Int {
switch self {
case .power: return 3
case .divide, .times: return 2
case .plus, .minus: return 1
}
}
var leftAssociative: Bool {
switch self {
case .power: return false
case .plus, .minus, .times, .divide: return true
}
}
func apply(_ a: Double, _ b: Double) -> Double {
switch self {
case .power: return pow(b, a)
case .divide: return b / a
case .times: return a * b
case .plus: return a + b
case .minus: return b - a
}
}
}
private extension Scanner {
func scanOperator() -> ShuntingYard.Operator? {
for op in ShuntingYard.Operator.allCases {
if scanString(op.rawValue) != nil {
return op
}
}
return nil
}
}
func testShuntingYard() {
func test(_ x: String) {
print(x,"=", ShuntingYard.evaluate(x))
}
test("3 + 4 * 5")
test("4 * 5 + 3")
test("2 ^ 3 ^ 4")
test("10.5 - 4 * 5")
test("2 + 3 ^ 4")
test("2 * 3 ^ 4")
test("3 ^ 4")
}
================================================
FILE: data_structures/Linked List/LinkedList.swift
================================================
import Foundation
public class Node<Value> {
public var value: Value?
public var next: Node?
public init(value: Value? = nil, next: Node<Value>? = nil) {
self.value = value
self.next = next
}
}
extension Node: CustomStringConvertible {
public var description: String {
guard let next = next else {
return "\(String(describing: value))"
}
return "\(String(describing: value)) -> " + String(describing: next) + " "
}
}
public struct LinkedList<Value> {
public var head: Node<Value>?
public var tail: Node<Value>?
public init() {}
public var isEmpty: Bool {
return head == nil
}
public mutating func push(_ value: Value) {
head = Node(value: value, next: head)
if tail == nil {
tail = head
}
}
public mutating func append(_ value: Value) {
guard !isEmpty else {
push(value)
return
}
tail!.next = Node(value: value)
tail = tail!.next
}
public func node(at index: Int) -> Node<Value>? {
var currentNode = head
var currentIndex = 0
while currentNode != nil && currentIndex < index {
currentNode = currentNode!.next
currentIndex += 1
}
return currentNode
}
@discardableResult
public mutating func insert(_ value: Value,
after node: Node<Value>) -> Node<Value> {
guard tail !== node else {
append(value)
return tail!
}
node.next = Node(value: value, next: node.next)
return node.next!
}
@discardableResult
public mutating func pop() -> Value? {
defer {
head = head?.next
if isEmpty {
tail = nil
}
}
return head?.value
}
@discardableResult
public mutating func removeLast() -> Value? {
guard let head = head else {
return nil
}
guard head.next != nil else {
return pop()
}
var prev = head
var current = head
while let next = current.next {
prev = current
current = next
}
prev.next = nil
tail = prev
return current.value
}
@discardableResult
public mutating func remove(after node: Node<Value>) -> Value? {
defer {
if node.next === tail {
tail = node
}
node.next = node.next?.next
}
return node.next?.value
}
}
extension LinkedList: CustomStringConvertible {
public var description: String {
guard let head = head else {
return "Empty list"
}
return String(describing: head)
}
}
// Below you can find a testing Scenario for Playground.
/*
import UIKit
// Test Linked List
let node1 = Node(value: 1)
let node2 = Node(value: 2)
let node3 = Node(value: 3)
node1.next = node2
node2.next = node3
print(node1)
var list = LinkedList<Int>()
list.push(3)
list.push(2)
list.push(1)
print(list)
var listAppend = LinkedList<Int>()
listAppend.append(1)
listAppend.append(2)
listAppend.append(3)
print(listAppend)
*/
================================================
FILE: data_structures/Stack/stack.swift
================================================
import Foundation
public struct Stack<T> {
private var elements = [T]()
public mutating func push(_ element: T) {
elements.append(element)
}
public mutating func pop() -> T? {
return elements.popLast()
}
public var isEmpty: Bool {
return elements.isEmpty
}
public var count: Int {
return elements.count
}
public var peek: T? {
return elements.last
}
}
// The code below can be used for testing
var stack = Stack<Int>()
stack.push(10)
stack.push(20)
stack.push(30)
print(stack.count)
print(stack.peek)
print(stack.isEmpty)
print(stack.pop())
print(stack.pop())
print(stack.pop())
print(stack.isEmpty)
print(stack.count)
================================================
FILE: data_structures/doubly_linked_list/DoublyLinkedList.swift
================================================
import Foundation
public class Node<Value> {
public var value: Value?
public var next: Node?
public var prev: Node?
public init(value: Value? = nil, next: Node<Value>? = nil, prev: Node<Value>? = nil) {
self.value = value
self.next = next
self.prev = prev
}
}
extension Node: CustomStringConvertible {
public var description: String {
guard let next: Node<Value> = self.next else {
return "\(String(describing: value))"
}
return "\(String(describing: value)) <-> \(String(describing: next)) "
}
}
public struct DoublyLinkedList<Value> {
public var head: Node<Value>?
public var tail: Node<Value>?
public var count: Int = 0
public var isEmpty: Bool {
return head == nil
}
public mutating func push(_ value: Value) {
let new: Node<Value> = Node(value: value, next: head)
if head != nil { head!.prev = new }
head = new
if tail == nil { tail = head }
count += 1
}
public mutating func append(_ value: Value) {
guard !isEmpty else {
push(value)
return
}
tail!.next = Node(value: value, prev: tail)
tail = tail!.next
count += 1
}
@discardableResult
public mutating func insert(_ value: Value,
after node: Node<Value>) -> Node<Value> {
guard tail !== node else {
append(value)
return tail!
}
var new: Node<Value> = Node(value: value, next: node.next, prev: node)
node.next?.prev = new
node.next = new
count += 1
return node.next!
}
@discardableResult
public mutating func insert(_ value: Value,
before node: Node<Value>) -> Node<Value> {
guard head !== node else {
push(value)
return head!
}
var new: Node<Value> = Node(value: value, next: node, prev: node.prev)
node.prev?.next = new
node.prev = new
count += 1
return node.prev!
}
public func node(at index: Int) -> Node<Value>? {
guard index > -1 || index < count else { return nil }
let startFromTail: Bool = index > count / 2
var currentNode: Node<Value>? = startFromTail ? tail : head
var currentIndex: Int = startFromTail ? count - 1 : 0
var change: Int = startFromTail ? -1 : 1
while currentNode != nil {
if currentIndex == index { break }
currentNode = startFromTail ? currentNode!.prev : currentNode!.next
currentIndex += change
}
return currentNode
}
@discardableResult
public mutating func pop() -> Value? {
defer {
head = head?.next
count -= 1
if isEmpty {
tail = nil
} else {
head!.prev = nil
}
}
return head?.value
}
@discardableResult
public mutating func removeLast() -> Value? {
defer {
tail = tail?.prev
count -= 1
if isEmpty {
head = nil
} else {
tail!.next = nil
}
}
return tail?.value
}
@discardableResult
public mutating func remove(after node: Node<Value>) -> Value? {
defer {
if node.next != nil {
count -= 1
}
if node.next === tail {
tail = node
}
if let next2node: Node<Value> = node.next?.next {
next2node.prev = node
}
node.next = node.next?.next
}
return node.next?.value
}
@discardableResult
public mutating func remove(before node: Node<Value>) -> Value? {
defer {
if node.prev != nil {
count -= 1
}
if node.prev === head {
head = node
}
if let prev2node: Node<Value> = node.prev?.prev {
prev2node.next = node
}
node.prev = node.prev?.prev
}
return node.prev?.value
}
}
extension DoublyLinkedList: CustomStringConvertible {
public var description: String {
guard let head: Node<Value> = self.head else {
return "Empty list"
}
return String(describing: head)
}
}
// Here are testing scenarios to run in a Swift playground
/*
var list = DoublyLinkedList<Int>()
list.push(4)
list.push(2)
list.push(1)
list.append(6)
var n = list.node(at: 2)
list.insert(5, after: n!)
list.insert(3, before: n!)
print(list)
print(list.pop()!)
print(list.removeLast()!)
print(list.remove(after: n!)!)
print(list.remove(before: n!)!)
print(list.count)
*/
================================================
FILE: data_structures/heap/heap.swift
================================================
struct Heap<Element> {
let compare: (Element, Element) -> Bool
private var items : [Element]
init(_ items : [Element], compare: @escaping (Element, Element) -> Bool) {
self.compare = compare
self.items = items
for index in (0 ..< count / 2).reversed() {
heapify(index)
}
}
/// The minimum item on this heap or nil if the heap is empty
var min: Element? {
return items.first
}
/// The number of items on this heap
var count: Int {
return items.count
}
/// true if this heap is empty
var isEmpty: Bool {
return items.isEmpty
}
/// Removes and returns the minimum item from the heap.
/// - returns: The minimum item from the heap or nil if the heap is empty.
mutating func extractMin() -> Element? {
guard let result = items.first else { return nil }
items.removeFirst()
heapify(0)
return result
}
/// Inserts a new item into this heap
/// - parameter item: The new item to insert
mutating func insert(item : Element) {
items.append(item)
var i = items.count - 1
while i > 0 && compare(items[i], items[parent(i)]) {
items.swapAt(i, parent(i))
i = parent(i)
}
}
/// Restores the heap property starting at a given index
/// - parameter index: The index to start at
private mutating func heapify(_ index : Int) {
var minimumIndex = index
if left(index) < count && compare(items[left(index)], items[minimumIndex]) {
minimumIndex = left(index)
}
if right(index) < count && compare(items[right(index)], items[minimumIndex]) {
minimumIndex = right(index)
}
if minimumIndex != index {
items.swapAt(minimumIndex, index)
heapify(minimumIndex)
}
}
/// Returns the index of the left child of an item
private func left(_ index : Int) -> Int {
return 2 * index + 1
}
/// Returns the index of the right child of an item
private func right(_ index: Int) -> Int {
return 2 * index + 2
}
/// Returns the index of the parent of an item
private func parent(_ index: Int) -> Int {
return (index - 1) / 2
}
}
extension Heap: ExpressibleByArrayLiteral where Element: Comparable {
init(arrayLiteral elements: Element...) {
self.init(elements, compare: <)
}
init(_ elements: [Element]) {
self.init(elements, compare: <)
}
}
================================================
FILE: data_structures/queue/queue.swift
================================================
// Create simple queue
// Tejas Nanaware
struct Queue<T> {
private var elements: [T] = []
mutating func push(_ value: T) {
elements.append(value)
}
mutating func pop() -> T? {
guard !elements.isEmpty else {
return nil
}
return elements.removeFirst()
}
}
var queue = Queue<String>()
queue.push("One")
queue.push("Two")
queue.push("Three")
print(queue.pop())
print(queue)
print(queue.pop())
print(queue)
print(queue.pop())
print(queue)
================================================
FILE: data_structures/union_find/union_find.swift
================================================
class UnionFindNode {
var rank = 0
private var parent: UnionFindNode? = nil
func findRoot() -> UnionFindNode {
var x = self
while let parent = x.parent {
x.parent = parent.parent ?? parent
x = parent
}
return x
}
@discardableResult
static func union(_ x: UnionFindNode, _ y: UnionFindNode) -> UnionFindNode {
var x = x.findRoot()
var y = y.findRoot()
guard x !== y else { return x }
if x.rank < y.rank {
swap(&x, &y)
}
y.parent = x
if x.rank == y.rank {
x.rank = y.rank + 1
}
return x
}
static func inSameSet(_ x: UnionFindNode, _ y: UnionFindNode) -> Bool {
return x.findRoot() === y.findRoot()
}
}
func testUnionFind() {
let a = UnionFindNode()
let b = UnionFindNode()
let c = UnionFindNode()
print("a, b", UnionFindNode.inSameSet(a, b))
print("b, c", UnionFindNode.inSameSet(b, c))
print("a, c", UnionFindNode.inSameSet(a, c))
print("Joining a, b")
UnionFindNode.union(a, b)
print("a, b", UnionFindNode.inSameSet(a, b))
print("b, c", UnionFindNode.inSameSet(b, c))
print("a, c", UnionFindNode.inSameSet(a, c))
print("Joining b, c")
UnionFindNode.union(b, c)
print("a, b", UnionFindNode.inSameSet(a, b))
print("b, c", UnionFindNode.inSameSet(b, c))
print("a, c", UnionFindNode.inSameSet(a, c))
print("New node d")
let d = UnionFindNode()
print("a, d", UnionFindNode.inSameSet(a, d))
print("Joining d, c")
UnionFindNode.union(d, c)
print("a, d", UnionFindNode.inSameSet(a, d))
}
================================================
FILE: graph/BFS/BFS.swift
================================================
// MARK: - Basic requirement
struct Edge {
let from: Int
let to: Int
}
public class Node {
var val: Int
var neighbors: [Int]
public init(_ val: Int) {
self.val = val
self.neighbors = []
}
}
// MARK: - BFS implementation
func testBFS(edges: [Edge]) {
var graph = [Int: Node]()
for edge in edges {
graph[edge.from] = Node(edge.from)
graph[edge.to] = Node(edge.to)
}
for edge in edges {
graph[edge.from]?.neighbors.append(edge.to)
graph[edge.to]?.neighbors.append(edge.from)
}
var visited: [Bool] = Array(repeating: false, count: graph.count + 1)
var nodesOfCurrentLevel: [Int] = []
for node in 1...graph.count {
if visited[node] == false {
nodesOfCurrentLevel.append(node)
while(nodesOfCurrentLevel.isEmpty == false) {
var nodesOfNextLevel: [Int] = []
let sizeOfQueue = nodesOfCurrentLevel.count
for index in 0..<sizeOfQueue {
let currNode = nodesOfCurrentLevel[index]
if(visited[currNode] == true){
continue
}
print("\(currNode) ")
visited[currNode] = true
guard let neighbors = graph[currNode]?.neighbors else { continue }
for neigh in neighbors {
if visited[neigh] == false {
nodesOfNextLevel.append(neigh)
}
}
}
nodesOfCurrentLevel = nodesOfNextLevel
}
}
}
}
// MARK: - Input Graph
func setup() {
let edges = [
Edge(from: 1, to: 2),
Edge(from: 1, to: 4),
Edge(from: 2, to: 3),
Edge(from: 2, to: 4),
Edge(from: 2, to: 5),
Edge(from: 3, to: 5),
Edge(from: 4, to: 5),
Edge(from: 4, to: 6),
Edge(from: 5, to: 6),
Edge(from: 5, to: 6),
Edge(from: 6, to: 7),
]
testBFS(edges: edges)
}
setup()
================================================
FILE: graph/DFS/DFS.swift
================================================
// MARK: - Basic requirement
struct Edge {
let from: Int
let to: Int
}
public class Node {
var val: Int
var neighbors: [Int]
public init(_ val: Int) {
self.val = val
self.neighbors = []
}
}
// MARK: - DFS Recursion
func dfs(vertex: Int, visited: inout [Bool], graph: [Int: Node]) {
if visited[vertex] == true {
return
}
visited[vertex] = true
print("\(vertex) ")
guard let neighbors = graph[vertex] else { return }
for neighbor in neighbors.neighbors {
dfs(vertex: neighbor, visited: &visited, graph: graph)
}
}
func testDFS(edges: [Edge]) {
var graph = [Int: Node]()
for edge in edges {
graph[edge.from] = Node(edge.from)
graph[edge.to] = Node(edge.to)
}
for edge in edges {
graph[edge.from]?.neighbors.append(edge.to)
graph[edge.to]?.neighbors.append(edge.from)
}
var visited: [Bool] = Array(repeating: false, count: graph.count + 1)
for node in 1...graph.count {
if visited[node] == false {
dfs(vertex: node, visited: &visited, graph: graph)
}
}
}
// MARK: - setup
func setup() {
let edges = [
Edge(from: 1, to: 2),
Edge(from: 1, to: 4),
Edge(from: 2, to: 3),
Edge(from: 2, to: 4),
Edge(from: 2, to: 5),
Edge(from: 3, to: 5),
Edge(from: 4, to: 5),
Edge(from: 4, to: 6),
Edge(from: 5, to: 6),
Edge(from: 5, to: 6),
Edge(from: 6, to: 7),
]
testDFS(edges: edges)
}
================================================
FILE: graph/Graph.swift
================================================
struct GraphEdge<G: Graph> {
var from: G.Node
var to: G.Node
var value: G.EdgeValue
}
protocol Graph {
typealias Edge = GraphEdge<Self>
associatedtype Node: Equatable
associatedtype EdgeValue
func edges(from: Node) -> [Edge]
}
struct AdjacencyList<Node: Hashable, EdgeValue>: Graph {
typealias EdgeValue = EdgeValue
typealias Node = Node
var graph: [Node: [Edge]] = [:]
func edges(from node: Node) -> [Edge] {
graph[node, default: []]
}
mutating func insert(from: Node, to: Node, value: EdgeValue) {
graph[from, default: []].append(Edge(from: from, to: to, value: value))
}
var allEdges: [Edge] {
graph.values.flatMap { $0 }
}
}
extension AdjacencyList where EdgeValue == () {
mutating func insert(from: Node, to: Node) {
insert(from: from, to: to, value: ())
}
}
extension Graph {
func depthFirstSearch(start: Node, destination: Node) -> [Edge]? {
if start == destination {
return []
}
for edge in edges(from: start) {
if let path = depthFirstSearch(start: edge.to, destination: destination) {
return [edge] + path
}
}
return nil
}
}
extension Graph where Node: Hashable {
func breadthFirstSearch(start: Node, destination: Node) -> [Edge]? {
var queue: [(Node, [Edge])] = [(start, [])]
var visited: Set<Node> = [start]
while !queue.isEmpty {
let (current, path) = queue.removeFirst()
if current == destination {
return path
}
for edge in edges(from: current) where visited.insert(edge.to).inserted {
queue.append((edge.to, path + [edge]))
}
}
return nil
}
}
extension GraphEdge: CustomDebugStringConvertible {
var debugDescription: String {
if type(of: value) == Void.self {
return "\(from) -- \(to)"
} else {
return "\(from) -\(value)- \(to)"
}
}
}
var graph = AdjacencyList<String, Void>()
graph.insert(from: "a", to: "b")
graph.insert(from: "a", to: "d")
graph.insert(from: "b", to: "c")
graph.insert(from: "c", to: "d")
func test<G: Graph>(_ message: String, _ list: [GraphEdge<G>]?) {
print(message)
if let list = list {
for edge in list {
print(edge)
}
} else {
print("Not found")
}
print("")
}
test("Depth-first a -> d", graph.depthFirstSearch(start: "a", destination: "d"))
test("Depth-first a -> e", graph.depthFirstSearch(start: "a", destination: "e"))
test("Breadth-first a -> d", graph.breadthFirstSearch(start: "a", destination: "d"))
test("Breadth-first a -> e", graph.breadthFirstSearch(start: "a", destination: "e"))
================================================
FILE: graph/spanning_tree/dijkstra.swift
================================================
class Node : CustomStringConvertible {
// unique identifier required for each node
var identifier : Int
var distance : Int = Int.max
var edges = [Edge]()
var visited = false
var description: String {
var edgesString = String()
edges.forEach{ edgesString.append($0.description)}
return "{ Node, identifier: \(identifier.description) + Edges: \(edgesString) + }"
}
init(visited: Bool, identifier: Int, edges: [Edge]) {
self.visited = visited
self.identifier = identifier
self.edges = edges
}
static func == (lhs: Node, rhs: Node) -> Bool {
return lhs.identifier == rhs.identifier
}
}
class Edge {
var from: Node // does not actually need to be stored!
var to: Node
var weight: Int
var description : String {
return "{ Edge, from: \(from.identifier), to: \(to.identifier), weight: \(weight) }"
}
init(to: Node, from: Node, weight: Int) {
self.to = to
self.weight = weight
self.from = from
}
}
class Graph {
var nodes: [Node] = []
}
// Complete the quickestWayUp function below.
func setupGraphwith(edges: [[Int]]) -> Graph {
let graph = Graph()
// create all the nodes
// The first and last node need to be included, so need nodes from "to" and "from"
let nodeNames = Set ( edges.map{ $0[0] } + edges.map{ $0[1]} )
for node in nodeNames {
let newNode = Node(visited: false, identifier: node, edges: [])
graph.nodes.append(newNode)
}
// create all the edges to link the nodes
for edge in edges {
if let fromNode = graph.nodes.first(where: { $0.identifier == edge[0] }) {
if let toNode = graph.nodes.first(where: { $0.identifier == edge[1] }) {
let forwardEdge = Edge(to: toNode, from: fromNode, weight: edge[2])
fromNode.edges.append(forwardEdge)
}
}
}
return graph
}
func shortestPath (source: Int, destination: Int, graph: Graph) -> Int {
var currentNode = graph.nodes.first{ $0.identifier == source }!
currentNode.visited = true
currentNode.distance = 0
var toVisit = [Node]()
toVisit.append(currentNode)
while ( !toVisit.isEmpty) {
toVisit = toVisit.filter{ $0.identifier != currentNode.identifier }
currentNode.visited = true
// Go to each adjacent vertex and update the path length
for connectedEdge in currentNode.edges {
let dist = currentNode.distance + connectedEdge.weight
if (dist < connectedEdge.to.distance) {
connectedEdge.to.distance = dist
toVisit.append(connectedEdge.to)
if (connectedEdge.to.visited == true) {
connectedEdge.to.visited = false
}
}
}
currentNode.visited = true
//set current node to the smallest vertex
if !toVisit.isEmpty {
currentNode = toVisit.min(by: { (a, b) -> Bool in
return a.distance < b.distance
})!
}
if (currentNode.identifier == destination) {
return currentNode.distance
}
}
return -1
}
================================================
FILE: graph/spanning_tree/kruskal.swift
================================================
enum Kruskal {
struct Vertex {
let name: String
let node = UnionFindNode()
init(_ name: String) {
self.name = name
}
}
struct Edge {
let from: Vertex
let to: Vertex
let weight: Int
}
typealias Graph = [Edge]
static func kruskal(_ graph: Graph) -> Graph {
var edges = Heap(graph) { $0.weight < $1.weight }
var result: Graph = []
result.reserveCapacity(edges.count)
while let edge = edges.extractMin() {
guard !UnionFindNode.inSameSet(edge.from.node, edge.to.node) else {
continue
}
UnionFindNode.union(edge.from.node, edge.to.node)
result.append(edge)
}
return result
}
}
extension Kruskal.Vertex: CustomStringConvertible {
var description: String { name }
}
extension Kruskal.Edge: CustomStringConvertible {
var description: String { "\(from) --(\(weight))-- \(to)" }
}
func testKruskal() {
typealias Vertex = Kruskal.Vertex
typealias Edge = Kruskal.Edge
let A = Vertex("A")
let B = Vertex("B")
let C = Vertex("C")
let D = Vertex("D")
let E = Vertex("E")
let F = Vertex("F")
let G = Vertex("G")
let graph = [
Edge(from: A, to: B, weight: 7),
Edge(from: A, to: D, weight: 5),
Edge(from: B, to: C, weight: 8),
Edge(from: B, to: D, weight: 9),
Edge(from: B, to: E, weight: 7),
Edge(from: C, to: E, weight: 5),
Edge(from: D, to: E, weight: 15),
Edge(from: D, to: F, weight: 6),
Edge(from: E, to: F, weight: 8),
Edge(from: E, to: G, weight: 9),
Edge(from: F, to: G, weight: 11),
]
print(Kruskal.kruskal(graph).map { String(describing: $0) }.joined(separator: "\n") )
}
================================================
FILE: recursion/fibonacci.swift
================================================
// The Fibonacci numbers, commonly denoted F(n) form a sequence,
// called the Fibonacci sequence, such that # each number is the sum
// of the two preceding ones, starting from 0 and 1. That is,
//
// F(0) = 0, F(1) = 1
// F(n) = F(n - 1) + F(n - 2), for n > 1
//
// Given n, calculate F(n).
//
// @leticiafaleia
func fibonacci(_ number: Int) -> Int {
guard number > 1 else { return number }
return fibonacci(number - 1) + fibonacci(number - 2)
}
fibonacci(5)
================================================
FILE: sorts/BubbleSort.swift
================================================
import Foundation
extension Array where Element: Comparable {
func bubbleSort(by areInIncreasingOrder: ((Element, Element) -> Bool) = (<)) -> [Element] {
var data = self
for i in 0..<(data.count-1) {
for j in 0..<(data.count-i-1) where areInIncreasingOrder(data[j+1], data[j]) {
data.swapAt(j, j + 1)
}
}
return data
}
}
func swap<T: Comparable>(left: inout T, right: inout T) {
print("Swapping \(left) and \(right)")
let temp = right
right = left
left = temp
}
// The code below can be used for testing
// let numberList : Array<Int> = [8, 2, 10, 9, 7, 5]
// let results: Array<Int> = numberList.bubbleSort()
// print(results)
================================================
FILE: sorts/CocktailSort.swift
================================================
/*
Cocktail Sort (or Cocktail shaker sort) is a variation of Bubble sort.
The Bubble sort algorithm always traverses elements from left and moves the largest element
to its correct position in first iteration and second largest in second iteration and so on.
Cocktail Sort traverses through a given array in both directions alternatively.
*/
import Foundation
func cocktailSort<T: Comparable>(_ a: [T]) -> [T] {
var list = a
var swapped = true
var start = 0
var end = list.count - 1
while (swapped) {
swapped = false
for i in start..<end {
if (list[i] > list[i + 1]) {
list.swapAt(i, i+1)
swapped = true
}
}
if (!swapped) {
break
}
swapped = false
end -= 1
for index in stride(from: end-1, through: start, by: -1) {
if (list[index] > list[index + 1]) {
list.swapAt(index, index+1)
swapped = true
}
}
start += 1
}
return list
}
// The code below can be used for testing
//var numbers = [2, -4, 4, 6, 1, 12, 9, 0]
//numbers = cocktailSort(numbers)
//print(numbers)
================================================
FILE: sorts/InsertionSort.swift
================================================
import Foundation
func insertionSort<T>(_ array: [T], by comparison: (T, T) -> Bool) -> [T] {
guard array.count > 1 else { return array }
var sortedArray = array
for index in 1..<sortedArray.count {
var currentIndex = index
let temp = sortedArray[currentIndex]
while currentIndex > 0, comparison(temp, sortedArray[currentIndex - 1]) {
sortedArray[currentIndex] = sortedArray[currentIndex - 1]
currentIndex -= 1
}
sortedArray[currentIndex] = temp
}
return sortedArray
}
// The code below can be used for testing
/*
let numbers = [10, 1, 3, 8, 4, 2]
print(insertionSort(numbers, by: >))
print(insertionSort(numbers, by: <))
let names = ["Jack", "Paul", "Olivia", "Emma", "Michael"]
print(insertionSort(names, by: >))
print(insertionSort(names, by: <))
*/
================================================
FILE: sorts/MergeSort.swift
================================================
import Foundation
extension Array where Element: Comparable {
mutating func mergeSort(by comparison: (Element, Element) -> Bool) {
guard self.count > 1 else {
return
}
_mergeSort(from: 0, to: count - 1, by: comparison)
}
mutating private func _mergeSort(
from left: Int,
to right: Int,
by comparison: (Element, Element) -> Bool
) {
if left < right {
let mid = left + (right - left) / 2
_mergeSort(from: 0, to: mid, by: comparison)
_mergeSort(from: mid + 1, to: right, by: comparison)
_merge(from: left, mid: mid, to: right, by: comparison)
}
}
mutating private func _merge(
from left: Int,
mid: Int,
to right: Int,
by comparison: (Element, Element) -> Bool
) {
var copy = [Element](repeating: self[left], count: right - left + 1)
var (leftStartIndex, rightStartIndex, currentIndex) = (left, mid + 1, 0)
for _ in left ... right {
if leftStartIndex > mid {
copy[currentIndex] = self[rightStartIndex]
rightStartIndex += 1
} else if rightStartIndex > right {
copy[currentIndex] = self[leftStartIndex]
leftStartIndex += 1
} else if comparison(self[leftStartIndex], self[rightStartIndex]) {
copy[currentIndex] = self[leftStartIndex]
leftStartIndex += 1
} else {
copy[currentIndex] = self[rightStartIndex]
rightStartIndex += 1
}
currentIndex += 1
}
leftStartIndex = left
for i in copy.indices {
self[leftStartIndex] = copy[i]
leftStartIndex += 1
}
}
func mergeSorted(by comparison: (Element, Element) -> Bool) -> Array {
var copy = self
copy.mergeSort(by: comparison)
return copy
}
}
// The code below can be used for testing
// var numberList = [15, 2, 23, 11, 3, 9]
// debugPrint(numberList.mergeSorted(by: >))
// numberList.mergeSort(by: <)
// debugPrint(numberList)
================================================
FILE: sorts/PancakeSort.swift
================================================
/*
Pancake sorting is the mathematical problem of sorting a disordered stack
of pancakes in order of size when a spatula can be inserted at any
point in the stack and used to flip all pancakes above it.
*/
import Foundation
func flip(array: [Int], key: Int) -> [Int] {
var flippedArray = array
var pos = key
var start = 0
var aux = 0
while (start < pos) {
aux = flippedArray[start]
flippedArray[start] = flippedArray[pos]
flippedArray[pos] = aux
start += 1
pos -= 1
}
return flippedArray
}
func pancakeSort(_ array: [Int]) -> [Int] {
var list = array
var currentSize = list.count
for _ in (1 ..< currentSize).reversed() {
let listToSearch = list[0...currentSize-1]
let max = listToSearch.max() ?? 0
let indexOfMax = listToSearch.firstIndex(of: max) ?? 0
if indexOfMax != currentSize - 1 {
list = flip(array: list, key: indexOfMax)
list = flip(array: list, key: currentSize - 1)
}
currentSize -= 1
}
return list
}
// The code below can be used for testing
//var numbers = [2, 4, 6, 12, 3, -2, 9, 14, 22, 0, 18]
//numbers = pancakeSort(numbers)
//print(numbers)
================================================
FILE: sorts/QuickSort.swift
================================================
import Foundation
extension Array where Element: Comparable {
/// Sorts the array using the QuickSort algorithm in place.
///
/// The QuickSort algorithm sorts the array by first choosing a pivot. This pivot is used to rearrange
/// all elements, moving the smaller ones to the left of it. This operation is then recursevely applied
/// to the subarrays formed around the pivot.
mutating func quickSort() {
guard count > 1 else {
return
}
_quickSort(from: 0, to: count - 1)
}
mutating private func _quickSort(from left: Int, to right: Int) {
guard left < right, right - left > 0 else {
return
}
let pivotIndex = partition(from: left, to: right)
_quickSort(from: left, to: pivotIndex - 1)
_quickSort(from: pivotIndex + 1, to: right)
}
/// This method is where the pivot is chosen, so the smaller elements get moved to the left,
/// and the bigger ones to the right.
mutating private func partition(from left: Int, to right: Int) -> Int {
/// Chooses the pivot, which in this case is always the first element, which is not very efficient.
let pivotIndex = left
swapAt(pivotIndex, right)
let pivot = self[right]
var i = left
for j in i ..< right {
// If the element is smaller than the pivot, move it to the left.
if self[j] <= pivot {
swapAt(i, j)
i += 1
}
}
// Move the pivot to its right sorted position.
swapAt(i, right)
return i
}
/// Returns a sorted version of this array using the QuickSort algorithm.
func quickSorted() -> Array {
var copy = self
copy.quickSort()
return copy
}
}
// Use the following code to test it:
// var numbers = [1002, 42, 55, 124, 205]
// debugPrint(numbers.quickSorted())
//
// numbers.quickSort()
// debugPrint(numbers)
//
// The console should print:
// [42, 55, 124, 205, 1002]
// [42, 55, 124, 205, 1002]
================================================
FILE: sorts/SelectionSort.swift
================================================
import Foundation
extension Array where Element: Comparable {
func selectionSort() -> Array<Element> {
guard self.count > 1 else {
return self
}
var output: Array<Element> = self
for primaryindex in 0..<output.count {
var minimum = primaryindex
var secondaryindex = primaryindex + 1
while secondaryindex < output.count {
if output[minimum] > output[secondaryindex] {
minimum = secondaryindex
}
secondaryindex += 1
}
if primaryindex != minimum {
output.swapAt(primaryindex, minimum)
}
}
return output
}
}
// The code below can be used for testing
// let numberList : Array<Int> = [15, 2, 23, 11, 3, 9]
// let results: Array<Int> = numberList.selectionSort()
// print(results)
================================================
FILE: trees/tree.swift
================================================
import Foundation
public class TreeNode<T> {
public var value: T
public weak var parent: TreeNode?
public var children = [TreeNode<T>]()
public init(value: T) {
self.value = value
}
public func addChild(_ node: TreeNode<T>) {
children.append(node)
node.parent = self
}
}
/* Checks the node's value property, if there is no match, check the child nodes.
Repeat the same process recursively */
extension TreeNode where T: Equatable {
func search(_ value: T) -> TreeNode? {
if value == self.value {
return self
}
for child in children {
if let found = child.search(value) {
return found
}
}
return nil
}
}
// The code below can be used for testing
let tree = TreeNode<String>(value: "animals")
let reptilesNode = TreeNode<String>(value: "reptiles")
let mammalsNode = TreeNode<String>(value: "mammals")
let lizardsNode = TreeNode<String>(value: "lizards")
let snakesNode = TreeNode<String>(value: "snakes")
let dogsNode = TreeNode<String>(value: "dogs")
let humansNode = TreeNode<String>(value: "humans")
tree.addChild(reptilesNode)
tree.addChild(mammalsNode)
reptilesNode.addChild(lizardsNode)
reptilesNode.addChild(snakesNode)
mammalsNode.addChild(dogsNode)
mammalsNode.addChild(humansNode)
print(tree.search("humans")?.value)
print(tree.search("lizards")?.value)
print(tree.search("dragons")?.value)
gitextract_yelu_m4v/
├── .github/
│ └── workflows/
│ ├── .stale.yml
│ └── directory_workflow.yml
├── .gitignore
├── DIRECTORY.md
├── README.md
├── Search/
│ ├── BinarySearch.swift
│ └── LinearSearch.swift
├── algorithms/
│ ├── AI/
│ │ └── minimax/
│ │ ├── README.md
│ │ └── Sources/
│ │ ├── Minimax.playground/
│ │ │ ├── Contents.swift
│ │ │ ├── Sources/
│ │ │ │ ├── Model/
│ │ │ │ │ ├── Board/
│ │ │ │ │ │ ├── Board.swift
│ │ │ │ │ │ ├── BoardPosition.swift
│ │ │ │ │ │ └── BoardStatus.swift
│ │ │ │ │ ├── GameModel/
│ │ │ │ │ │ ├── DifficultLevel.swift
│ │ │ │ │ │ └── GameModel.swift
│ │ │ │ │ ├── Minimax/
│ │ │ │ │ │ ├── GameStateValue.swift
│ │ │ │ │ │ └── Minimax.swift
│ │ │ │ │ └── Player/
│ │ │ │ │ ├── Player.swift
│ │ │ │ │ ├── PlayerSymbol.swift
│ │ │ │ │ └── PlayerType.swift
│ │ │ │ └── View/
│ │ │ │ └── BoardView.swift
│ │ │ ├── contents.xcplayground
│ │ │ └── playground.xcworkspace/
│ │ │ ├── contents.xcworkspacedata
│ │ │ └── xcshareddata/
│ │ │ └── WorkspaceSettings.xcsettings
│ │ └── Tests/
│ │ ├── Tests/
│ │ │ ├── BoardTests.swift
│ │ │ ├── Info.plist
│ │ │ ├── MinimaxTests.swift
│ │ │ └── PlayerTests.swift
│ │ └── Tests.xcodeproj/
│ │ ├── project.pbxproj
│ │ └── project.xcworkspace/
│ │ ├── contents.xcworkspacedata
│ │ └── xcshareddata/
│ │ ├── IDEWorkspaceChecks.plist
│ │ └── WorkspaceSettings.xcsettings
│ ├── conversion/
│ │ ├── binary-to-decimal.swift
│ │ └── decimal-to-binary.swift
│ ├── palindrome/
│ │ ├── palindrome_indices.swift
│ │ ├── palindrome_recursion.swift
│ │ └── palindrome_reversed.swift
│ └── parsing/
│ └── shunting_yard/
│ └── shunting_yard.swift
├── data_structures/
│ ├── Linked List/
│ │ └── LinkedList.swift
│ ├── Stack/
│ │ └── stack.swift
│ ├── doubly_linked_list/
│ │ └── DoublyLinkedList.swift
│ ├── heap/
│ │ └── heap.swift
│ ├── queue/
│ │ └── queue.swift
│ └── union_find/
│ └── union_find.swift
├── graph/
│ ├── BFS/
│ │ └── BFS.swift
│ ├── DFS/
│ │ └── DFS.swift
│ ├── Graph.swift
│ └── spanning_tree/
│ ├── dijkstra.swift
│ └── kruskal.swift
├── recursion/
│ └── fibonacci.swift
├── sorts/
│ ├── BubbleSort.swift
│ ├── CocktailSort.swift
│ ├── InsertionSort.swift
│ ├── MergeSort.swift
│ ├── PancakeSort.swift
│ ├── QuickSort.swift
│ └── SelectionSort.swift
└── trees/
└── tree.swift
Condensed preview — 57 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (114K chars).
[
{
"path": ".github/workflows/.stale.yml",
"chars": 2443,
"preview": "# Configuration for probot-stale - https://github.com/probot/stale\n\n# Number of days of inactivity before an Issue or Pu"
},
{
"path": ".github/workflows/directory_workflow.yml",
"chars": 2879,
"preview": "name: directory_md\non: [push, pull_request]\n\njobs:\n MainSequence:\n name: DIRECTORY.md\n runs-on: ubuntu-latest\n "
},
{
"path": ".gitignore",
"chars": 10,
"preview": ".DS_Store\n"
},
{
"path": "DIRECTORY.md",
"chars": 5875,
"preview": "# List of all files\n\n## Algorithms\n * Ai\n * Minimax\n * Sources\n * Minimax.Playground\n * [Conten"
},
{
"path": "README.md",
"chars": 365,
"preview": "# The Algorithms - Swift\n\n### All algorithms implemented in Swift (for education)\n\nThese implementations are for learnin"
},
{
"path": "Search/BinarySearch.swift",
"chars": 764,
"preview": "import Foundation\n\npublic func binarySearch<T: Comparable>(_ a: [T], key: T) -> Int? {\n var lowerBound = 0\n var up"
},
{
"path": "Search/LinearSearch.swift",
"chars": 484,
"preview": "import Foundation\n\nfunc linearSearch<T: Equatable>(_ array: [T], _ object: T) -> Int? {\n for (index, obj) in array.enum"
},
{
"path": "algorithms/AI/minimax/README.md",
"chars": 2668,
"preview": "# Minimax algorithm\n\n<p align=\"center\"> <img src=\"Resources/image1.jpg\" {:height=\"50%\" width=\"50%\"} /> </p>\n\n## Runtime "
},
{
"path": "algorithms/AI/minimax/Sources/Minimax.playground/Contents.swift",
"chars": 260,
"preview": "import UIKit\nimport PlaygroundSupport\n\nlet boardSize = CGSize(width: 500, height: 550)\nlet boardView = BoardView(frame: "
},
{
"path": "algorithms/AI/minimax/Sources/Minimax.playground/Sources/Model/Board/Board.swift",
"chars": 5026,
"preview": "public struct Board {\n // MARK: -- Public variable's\n public var size: Int\n\n // MARK: -- Private variable's\n "
},
{
"path": "algorithms/AI/minimax/Sources/Minimax.playground/Sources/Model/Board/BoardPosition.swift",
"chars": 52,
"preview": "public typealias Position = (row: Int, column: Int)\n"
},
{
"path": "algorithms/AI/minimax/Sources/Minimax.playground/Sources/Model/Board/BoardStatus.swift",
"chars": 77,
"preview": "public enum BoardStatus {\n\n case continues\n\n case win\n\n case draw\n}\n"
},
{
"path": "algorithms/AI/minimax/Sources/Minimax.playground/Sources/Model/GameModel/DifficultLevel.swift",
"chars": 95,
"preview": "public enum DifficultLevel: Int {\n\n case easy = 2\n\n case medium = 3\n\n case hard = 5\n}\n"
},
{
"path": "algorithms/AI/minimax/Sources/Minimax.playground/Sources/Model/GameModel/GameModel.swift",
"chars": 2757,
"preview": "import Foundation\n\npublic class GameModel {\n // MARK: -- Public variable's\n public var board: Board!\n\n public v"
},
{
"path": "algorithms/AI/minimax/Sources/Minimax.playground/Sources/Model/Minimax/GameStateValue.swift",
"chars": 92,
"preview": "public enum GameStateValue: Int {\n\n case min = -1\n\n case null = 0\n\n case max = 1\n}\n"
},
{
"path": "algorithms/AI/minimax/Sources/Minimax.playground/Sources/Model/Minimax/Minimax.swift",
"chars": 3814,
"preview": "public func minimaxMove(board: Board, player: Player, opponent: Player, depth: Int) -> Position {\n var bestVal = Game"
},
{
"path": "algorithms/AI/minimax/Sources/Minimax.playground/Sources/Model/Player/Player.swift",
"chars": 281,
"preview": "public struct Player {\n // MARK: -- Public variable's\n public var type: PlayerType\n\n public var symbol: PlayerS"
},
{
"path": "algorithms/AI/minimax/Sources/Minimax.playground/Sources/Model/Player/PlayerSymbol.swift",
"chars": 104,
"preview": "public enum PlayerSymbol: String {\n\n case empty = \"\"\n\n case circle = \"⭕️\"\n\n case cross = \"❌\"\n}\n"
},
{
"path": "algorithms/AI/minimax/Sources/Minimax.playground/Sources/Model/Player/PlayerType.swift",
"chars": 62,
"preview": "public enum PlayerType {\n\n case computer\n\n case human\n}\n"
},
{
"path": "algorithms/AI/minimax/Sources/Minimax.playground/Sources/View/BoardView.swift",
"chars": 7377,
"preview": "import UIKit\n\npublic class BoardView: UIView {\n // MARK: -- Public\n public var gameModel: GameModel!\n\n public v"
},
{
"path": "algorithms/AI/minimax/Sources/Minimax.playground/contents.xcplayground",
"chars": 212,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n<playground version='5.0' target-platform='ios' buildActiveSchem"
},
{
"path": "algorithms/AI/minimax/Sources/Minimax.playground/playground.xcworkspace/contents.xcworkspacedata",
"chars": 136,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Workspace\n version = \"1.0\">\n <FileRef\n location = \"group:\">\n </FileRe"
},
{
"path": "algorithms/AI/minimax/Sources/Minimax.playground/playground.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings",
"chars": 264,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
},
{
"path": "algorithms/AI/minimax/Sources/Tests/Tests/BoardTests.swift",
"chars": 4947,
"preview": "import XCTest\n\nclass BoardTests: XCTestCase {\n\n private var sut: Board!\n\n private var boardSize = 3\n\n override "
},
{
"path": "algorithms/AI/minimax/Sources/Tests/Tests/Info.plist",
"chars": 727,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
},
{
"path": "algorithms/AI/minimax/Sources/Tests/Tests/MinimaxTests.swift",
"chars": 2436,
"preview": "import XCTest\n\nclass MinimaxTests: XCTestCase {\n override func setUp() {\n super.setUp()\n }\n\n override fu"
},
{
"path": "algorithms/AI/minimax/Sources/Tests/Tests/PlayerTests.swift",
"chars": 504,
"preview": "import XCTest\n\nclass PlayerTests: XCTestCase {\n\n private var sut: Player!\n\n private var playerType: PlayerType = ."
},
{
"path": "algorithms/AI/minimax/Sources/Tests/Tests.xcodeproj/project.pbxproj",
"chars": 15996,
"preview": "// !$*UTF8*$!\n{\n\tarchiveVersion = 1;\n\tclasses = {\n\t};\n\tobjectVersion = 50;\n\tobjects = {\n\n/* Begin PBXBuildFile section *"
},
{
"path": "algorithms/AI/minimax/Sources/Tests/Tests.xcodeproj/project.xcworkspace/contents.xcworkspacedata",
"chars": 135,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Workspace\n version = \"1.0\">\n <FileRef\n location = \"self:\">\n </FileRef"
},
{
"path": "algorithms/AI/minimax/Sources/Tests/Tests.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist",
"chars": 238,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
},
{
"path": "algorithms/AI/minimax/Sources/Tests/Tests.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings",
"chars": 264,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
},
{
"path": "algorithms/conversion/binary-to-decimal.swift",
"chars": 566,
"preview": "import Foundation\n\n/// This function accepts a binary number as String and converts it to decimal as Int. \n/// If it's n"
},
{
"path": "algorithms/conversion/decimal-to-binary.swift",
"chars": 342,
"preview": "/// This function accepts a non-negative number and returns its binary form as String.\npublic func convertDecimalToBinar"
},
{
"path": "algorithms/palindrome/palindrome_indices.swift",
"chars": 1147,
"preview": "// A palindrome is a string that reads the same forwards and backwards.\n//\n// Examples: \"level\", \"radar\", \"madam\", \"A ma"
},
{
"path": "algorithms/palindrome/palindrome_recursion.swift",
"chars": 1464,
"preview": "// A palindrome is a string that reads the same forwards and backwards.\n//\n// Examples: \"level\", \"radar\", \"madam\", \"A ma"
},
{
"path": "algorithms/palindrome/palindrome_reversed.swift",
"chars": 521,
"preview": "// A palindrome is a string that reads the same forwards and backwards.\n//\n// Examples: \"level\", \"radar\", \"madam\", \"A ma"
},
{
"path": "algorithms/parsing/shunting_yard/shunting_yard.swift",
"chars": 2461,
"preview": "import Foundation\n\nenum ShuntingYard {\n enum Operator: String, CaseIterable {\n case power = \"^\"\n case p"
},
{
"path": "data_structures/Linked List/LinkedList.swift",
"chars": 3305,
"preview": "import Foundation\n\npublic class Node<Value> {\n public var value: Value?\n public var next: Node?\n \n public in"
},
{
"path": "data_structures/Stack/stack.swift",
"chars": 734,
"preview": "import Foundation\n\npublic struct Stack<T> {\n private var elements = [T]()\n \n public mutating func push(_ elemen"
},
{
"path": "data_structures/doubly_linked_list/DoublyLinkedList.swift",
"chars": 4915,
"preview": "import Foundation\n\npublic class Node<Value> {\n public var value: Value?\n public var next: Node?\n public var pre"
},
{
"path": "data_structures/heap/heap.swift",
"chars": 2565,
"preview": "struct Heap<Element> {\n let compare: (Element, Element) -> Bool\n private var items : [Element]\n\n init(_ items :"
},
{
"path": "data_structures/queue/queue.swift",
"chars": 473,
"preview": "// Create simple queue\n// Tejas Nanaware\n\nstruct Queue<T> {\n private var elements: [T] = []\n\n mutating func push(_ val"
},
{
"path": "data_structures/union_find/union_find.swift",
"chars": 1692,
"preview": "class UnionFindNode {\n var rank = 0\n\n private var parent: UnionFindNode? = nil\n\n func findRoot() -> UnionFindNo"
},
{
"path": "graph/BFS/BFS.swift",
"chars": 2103,
"preview": "// MARK: - Basic requirement\nstruct Edge {\n let from: Int\n let to: Int\n}\n\npublic class Node {\n var val: Int\n "
},
{
"path": "graph/DFS/DFS.swift",
"chars": 1546,
"preview": "// MARK: - Basic requirement\nstruct Edge {\n let from: Int\n let to: Int\n}\n\npublic class Node {\n var val: Int\n "
},
{
"path": "graph/Graph.swift",
"chars": 2811,
"preview": "struct GraphEdge<G: Graph> {\n var from: G.Node\n var to: G.Node\n var value: G.EdgeValue\n}\n\nprotocol Graph {\n "
},
{
"path": "graph/spanning_tree/dijkstra.swift",
"chars": 3332,
"preview": "class Node : CustomStringConvertible {\n // unique identifier required for each node\n var identifier : Int\n var "
},
{
"path": "graph/spanning_tree/kruskal.swift",
"chars": 1830,
"preview": "enum Kruskal {\n struct Vertex {\n let name: String\n let node = UnionFindNode()\n\n init(_ name: Str"
},
{
"path": "recursion/fibonacci.swift",
"chars": 470,
"preview": "// The Fibonacci numbers, commonly denoted F(n) form a sequence,\n// called the Fibonacci sequence, such that # each numb"
},
{
"path": "sorts/BubbleSort.swift",
"chars": 749,
"preview": "import Foundation\n\nextension Array where Element: Comparable {\n\n func bubbleSort(by areInIncreasingOrder: ((Element, "
},
{
"path": "sorts/CocktailSort.swift",
"chars": 1213,
"preview": "\n/*\n Cocktail Sort (or Cocktail shaker sort) is a variation of Bubble sort.\n The Bubble sort algorithm always traverses "
},
{
"path": "sorts/InsertionSort.swift",
"chars": 867,
"preview": "import Foundation\n\nfunc insertionSort<T>(_ array: [T], by comparison: (T, T) -> Bool) -> [T] {\n guard array.count > 1"
},
{
"path": "sorts/MergeSort.swift",
"chars": 1801,
"preview": "\nimport Foundation\n\nextension Array where Element: Comparable {\n\t\n\tmutating func mergeSort(by comparison: (Element, Elem"
},
{
"path": "sorts/PancakeSort.swift",
"chars": 1268,
"preview": "\n/*\n Pancake sorting is the mathematical problem of sorting a disordered stack\n of pancakes in order of size when a spat"
},
{
"path": "sorts/QuickSort.swift",
"chars": 2153,
"preview": "import Foundation\n\nextension Array where Element: Comparable {\n /// Sorts the array using the QuickSort algorithm in "
},
{
"path": "sorts/SelectionSort.swift",
"chars": 1068,
"preview": "import Foundation\n\nextension Array where Element: Comparable {\nfunc selectionSort() -> Array<Element> { \n \n "
},
{
"path": "trees/tree.swift",
"chars": 1464,
"preview": "import Foundation\n\npublic class TreeNode<T> {\n public var value: T\n\n public weak var parent: TreeNode?\n public "
}
]
About this extraction
This page contains the full source code of the TheAlgorithms/Swift GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 57 files (101.8 KB), approximately 28.6k tokens. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.