├── .gitignore
├── LICENSE
├── Pathfinder-Demo
├── AppDelegate.swift
├── Base.lproj
│ └── Main.storyboard
├── GridView.swift
├── Images.xcassets
│ ├── AppIcon.appiconset
│ │ ├── Contents.json
│ │ ├── Icon-40.png
│ │ ├── Icon-40@2x.png
│ │ ├── Icon-40@3x.png
│ │ ├── Icon-60@2x.png
│ │ ├── Icon-60@3x.png
│ │ ├── Icon-72.png
│ │ ├── Icon-72@2x.png
│ │ ├── Icon-76.png
│ │ ├── Icon-76@2x.png
│ │ ├── Icon-83.5@2x.png
│ │ ├── Icon-Small-50.png
│ │ ├── Icon-Small-50@2x.png
│ │ ├── Icon-Small.png
│ │ ├── Icon-Small@2x.png
│ │ ├── Icon-Small@3x.png
│ │ ├── Icon.png
│ │ ├── Icon@2x.png
│ │ ├── NotificationIcon@2x.png
│ │ ├── NotificationIcon@3x.png
│ │ ├── NotificationIcon~ipad.png
│ │ ├── NotificationIcon~ipad@2x.png
│ │ └── ios-marketing.png
│ └── LaunchImage.launchimage
│ │ └── Contents.json
├── Info.plist
├── NodeView.swift
├── Pathfinder-Demo-Bridging-Header.h
└── ViewController.swift
├── Pathfinder.xcodeproj
├── project.pbxproj
├── project.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcshareddata
│ │ └── IDEWorkspaceChecks.plist
└── xcuserdata
│ └── ilijatovilo.xcuserdatad
│ └── xcschemes
│ ├── Pathfinder-Demo.xcscheme
│ ├── Pathfinder.xcscheme
│ ├── PathfinderTests.xcscheme
│ └── xcschememanagement.plist
├── Pathfinder
├── AStarAlgorithm.swift
├── Algorithm.swift
├── Coordinates.swift
├── Grid.swift
├── Helpers.swift
├── HeuristicFunction.swift
├── IndexedArray.swift
├── Info.plist
├── Map.swift
├── Matrix.swift
├── Node.swift
└── Pathfinder.h
├── README.md
├── demo.png
└── demo2.png
/.gitignore:
--------------------------------------------------------------------------------
1 | # Adapted from https://github.com/github/gitignore/blob/master/Objective-C.gitignore
2 |
3 | # Finder
4 | .DS_Store
5 |
6 | # Xcode
7 | ## Build generated
8 | build/
9 | DerivedData/
10 |
11 | ## Various settings
12 | *.pbxuser
13 | !default.pbxuser
14 | *.mode1v3
15 | !default.mode1v3
16 | *.mode2v3
17 | !default.mode2v3
18 | *.perspectivev3
19 | !default.perspectivev3
20 | xcuserdata/
21 |
22 | ## Other
23 | *.moved-aside
24 | *.xccheckout
25 | *.xcscmblueprint
26 |
27 | ## Obj-C/Swift specific
28 | *.hmap
29 | *.ipa
30 | *.dSYM.zip
31 | *.dSYM
32 |
33 | # CocoaPods
34 | #
35 | # We recommend against adding the Pods directory to your .gitignore. However
36 | # you should judge for yourself, the pros and cons are mentioned at:
37 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
38 |
39 | Pods/
40 |
41 | # Add this line if you want to avoid checking in source code from the Xcode workspace
42 | # *.xcworkspace
43 |
44 | # Carthage
45 | #
46 | # Add this line if you want to avoid checking in source code from Carthage dependencies.
47 | # Carthage/Checkouts
48 |
49 | Carthage/Build
50 |
51 | # fastlane
52 | #
53 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the
54 | # screenshots whenever they are needed.
55 | # For more information about the recommended setup visit:
56 | # https://docs.fastlane.tools/best-practices/source-control/#source-control
57 |
58 | fastlane/report.xml
59 | fastlane/Preview.html
60 | fastlane/screenshots/**/*.png
61 | fastlane/test_output
62 |
63 | # Code Injection
64 | #
65 | # After new code Injection tools there's a generated folder /iOSInjectionProject
66 | # https://github.com/johnno1962/injectionforxcode
67 |
68 | iOSInjectionProject/
69 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2014 Ilija Tovilo
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/Pathfinder-Demo/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.swift
3 | // Pathfinder-Demo
4 | //
5 | // Created by Ilija Tovilo on 15/08/14.
6 | // Copyright (c) 2014 Ilija Tovilo
7 | //
8 | // Permission is hereby granted, free of charge, to any person obtaining a copy
9 | // of this software and associated documentation files (the "Software"), to deal
10 | // in the Software without restriction, including without limitation the rights
11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | // copies of the Software, and to permit persons to whom the Software is
13 | // furnished to do so, subject to the following conditions:
14 | //
15 | // The above copyright notice and this permission notice shall be included in all
16 | // copies or substantial portions of the Software.
17 | //
18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 | // SOFTWARE.
25 |
26 | import UIKit
27 |
28 | @UIApplicationMain
29 | class AppDelegate: UIResponder, UIApplicationDelegate {
30 |
31 | var window: UIWindow?
32 |
33 |
34 | private func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
35 | // Override point for customization after application launch.
36 | return true
37 | }
38 |
39 | func applicationWillResignActive(_ application: UIApplication) {
40 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
41 | // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.
42 | }
43 |
44 | func applicationDidEnterBackground(_ application: UIApplication) {
45 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
46 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
47 | }
48 |
49 | func applicationWillEnterForeground(_ application: UIApplication) {
50 | // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
51 | }
52 |
53 | func applicationDidBecomeActive(_ application: UIApplication) {
54 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
55 | }
56 |
57 | func applicationWillTerminate(_ application: UIApplication) {
58 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
59 | }
60 |
61 |
62 | }
63 |
64 |
--------------------------------------------------------------------------------
/Pathfinder-Demo/Base.lproj/Main.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
42 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
--------------------------------------------------------------------------------
/Pathfinder-Demo/GridView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // GridView.swift
3 | // Pathfinder
4 | //
5 | // Created by Ilija Tovilo on 15/08/14.
6 | // Copyright (c) 2014 Ilija Tovilo
7 | //
8 | // Permission is hereby granted, free of charge, to any person obtaining a copy
9 | // of this software and associated documentation files (the "Software"), to deal
10 | // in the Software without restriction, including without limitation the rights
11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | // copies of the Software, and to permit persons to whom the Software is
13 | // furnished to do so, subject to the following conditions:
14 | //
15 | // The above copyright notice and this permission notice shall be included in all
16 | // copies or substantial portions of the Software.
17 | //
18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 | // SOFTWARE.
25 |
26 | import UIKit
27 | import Pathfinder
28 |
29 | private let _gridSize = 20
30 |
31 | enum TouchOperation {
32 | case Start, End, Draw, Erase
33 | }
34 |
35 | class GridView: UIView {
36 |
37 | private var _nodes: Matrix!
38 | private var _grid: Grid!
39 | private var _startNodeView: NodeView!
40 | private var _endNodeView: NodeView!
41 | private var _touchOperation = TouchOperation.Draw
42 | private var _touchNode: NodeView?
43 | private var _nodeViews: Matrix!
44 | private var _cachedPath: [Node]?
45 |
46 | override func awakeFromNib() {
47 | _nodeViews = Matrix(width: _gridSize, height: _gridSize, repeatedValue: { (x, y) in
48 | return nil
49 | })
50 | _nodes = Matrix(width: _gridSize, height: _gridSize) {
51 | (x, y) -> Node in
52 | return Node(coordinates: Coordinates2D(x: x, y: y))
53 | }
54 | _grid = Grid(nodes: self._nodes)
55 | // Create a node view for all nodes
56 | for (x, y, _) in _nodes {
57 | _nodeViews[x,y] = addNodeView(x, y)
58 | }
59 | // Reset type's of node views.
60 | reset()
61 | }
62 |
63 | public func viewControllerDidLayoutSubviews() {
64 | let nodeWidth: CGFloat = bounds.size.width / CGFloat(_gridSize)
65 | let nodeHeight: CGFloat = bounds.size.height / CGFloat(_gridSize)
66 | for (x, y, _) in _nodes {
67 | let nodeView = _nodeViews[x,y]
68 | nodeView!.frame = CGRect(x: CGFloat(x) * nodeWidth, y: CGFloat(y) * nodeHeight, width: nodeWidth, height: nodeHeight)
69 | }
70 | }
71 |
72 | public func reset() {
73 | // Reset type's of node views, making all .Empty except for one
74 | // .Start and one .End .
75 | for (x, y, _) in _nodes {
76 | let nodeView = _nodeViews[x,y]!
77 | if x == 0 && y == 0 {
78 | nodeView.type = .Start
79 | _startNodeView = nodeView
80 | } else if x == _gridSize - 1 && y == _gridSize - 1 {
81 | nodeView.type = .End
82 | _endNodeView = nodeView
83 | } else {
84 | nodeView.type = .Empty
85 | }
86 | }
87 | resetPath()
88 | }
89 |
90 | func addNodeView(_ x: Int, _ y: Int) -> NodeView {
91 | let nodeWidth: CGFloat = bounds.size.width / CGFloat(_gridSize)
92 | let nodeHeight: CGFloat = bounds.size.height / CGFloat(_gridSize)
93 |
94 | let node = _nodes[x, y]
95 | let nodeView = NodeView(
96 | frame: CGRect(x: CGFloat(x) * nodeWidth, y: CGFloat(y) * nodeHeight, width: nodeWidth, height: nodeHeight),
97 | node: node
98 | )
99 | addSubview(nodeView)
100 |
101 | return nodeView
102 | }
103 |
104 | override func touchesBegan(_ touches: Set, with event: UIEvent?) {
105 | for touch in touches {
106 | let view = hitTest(touch.location(in: self), with: event)
107 | if let nodeView = view as? NodeView {
108 | switch nodeView.type {
109 | case .Start:
110 | _touchOperation = .Start
111 | case .End:
112 | _touchOperation = .End
113 | case .Empty:
114 | _touchOperation = .Draw
115 | case .Obstacle:
116 | _touchOperation = .Erase
117 | }
118 | touchMoveTo(nodeView: nodeView)
119 | break;
120 | }
121 | }
122 | }
123 |
124 | override func touchesMoved(_ touches: Set, with event: UIEvent?) {
125 | for touch in touches {
126 | let view = hitTest(touch.location(in: self), with: event)
127 | if let nodeView = view as? NodeView {
128 | touchMoveTo(nodeView: nodeView)
129 | break;
130 | }
131 | }
132 | }
133 |
134 | override func touchesEnded(_ touches: Set, with event: UIEvent?) {
135 | for touch in touches {
136 | let view = hitTest(touch.location(in: self), with: event)
137 | if let nodeView = view as? NodeView {
138 | touchMoveTo(nodeView: nodeView)
139 | break;
140 | }
141 | }
142 | _touchOperation = .Draw
143 | _touchNode = nil
144 | }
145 |
146 | func touchMoveTo(nodeView: NodeView) {
147 | if _touchNode === nodeView { return }
148 | switch _touchOperation {
149 | case .Start:
150 | switch nodeView.type {
151 | case .Empty:
152 | _startNodeView.type = .Empty
153 | _startNodeView = nodeView
154 | _startNodeView.type = .Start
155 | default:
156 | break
157 | }
158 | case .End:
159 | switch nodeView.type {
160 | case .Empty:
161 | _endNodeView.type = .Empty
162 | _endNodeView = nodeView
163 | _endNodeView.type = .End
164 | default:
165 | break
166 | }
167 | default:
168 | let coord2 = nodeView.node.coordinates as! Coordinates2D
169 | if (_touchNode == nil) {
170 | plotPoint(coord2.x,coord2.y)
171 | } else {
172 | let coord1 = _touchNode?.node.coordinates as! Coordinates2D
173 | plotLine(coord1.x,coord1.y,coord2.x,coord2.y)
174 | }
175 | }
176 | _touchNode = nodeView
177 | }
178 |
179 | func plotLine(_ x0:Int,_ y0:Int,_ x1:Int,_ y1:Int) {
180 | // Bresenham's line algorithm
181 | // https://en.wikipedia.org/wiki/Bresenham%27s_line_algorithm#Algorithm
182 | // Creative Commons Attribution-ShareAlike 3.0 License
183 | if abs(y1 - y0) < abs(x1 - x0) {
184 | if x0 > x1 {
185 | plotLineLow(x1, y1, x0, y0)
186 | } else {
187 | plotLineLow(x0, y0, x1, y1)
188 | }
189 | } else {
190 | if y0 > y1 {
191 | plotLineHigh(x1, y1, x0, y0)
192 | } else {
193 | plotLineHigh(x0, y0, x1, y1)
194 | }
195 | }
196 | }
197 |
198 | func plotLineLow(_ x0:Int,_ y0:Int,_ x1:Int,_ y1:Int) {
199 | let dx = x1 - x0
200 | var dy = y1 - y0
201 | var yinc = 1
202 | if dy < 0 {
203 | yinc = -1
204 | dy = -dy
205 | }
206 | var D = 2*dy - dx
207 | var y = y0
208 | for x in x0...x1 {
209 | plotPoint(x,y)
210 | if D > 0 {
211 | y = y + yinc
212 | D = D - 2*dx
213 | }
214 | D = D + 2*dy
215 | }
216 | }
217 |
218 | func plotLineHigh(_ x0:Int,_ y0:Int,_ x1:Int,_ y1:Int) {
219 | var dx = x1 - x0
220 | let dy = y1 - y0
221 | var xinc = 1
222 | if dx < 0 {
223 | xinc = -1
224 | dx = -dx
225 | }
226 | var D = 2*dx - dy
227 | var x = x0
228 | for y in y0...y1 {
229 | plotPoint(x,y)
230 | if D > 0 {
231 | x = x + xinc
232 | D = D - 2*dy
233 | }
234 | D = D + 2*dx
235 | }
236 | }
237 |
238 | func plotPoint(_ x:Int,_ y:Int) {
239 | let nodeView = _nodeViews[x,y]!
240 | switch nodeView.type {
241 | case .Empty:
242 | if _touchOperation == .Draw {
243 | nodeView.type = .Obstacle
244 | }
245 | case .Obstacle:
246 | if _touchOperation == .Erase {
247 | nodeView.type = .Empty
248 | }
249 | default:
250 | break
251 | }
252 | }
253 |
254 | func resetPath() {
255 | for (_, _, node) in _nodes {
256 | node.reset()
257 | }
258 |
259 | for (_, _, nodeView) in _nodeViews {
260 | if nodeView!.node.parent != nil { nodeView!.node.parent = nil }
261 | if nodeView!.partOfPath { nodeView!.partOfPath = false }
262 |
263 | nodeView!.setNeedsDisplay()
264 | }
265 | }
266 |
267 | internal func findPath() {
268 | resetPath()
269 |
270 | self._cachedPath = AStarAlgorithm.findPathInMap(self._grid, startNode: self._startNodeView.node, endNode: self._endNodeView.node)
271 |
272 | for node in _cachedPath! {
273 | let coords = node.coordinates as! Coordinates2D
274 | if let nodeView = _nodeViews[coords.x, coords.y] {
275 | nodeView.partOfPath = true
276 | }
277 | }
278 |
279 | for (x, y, _) in _nodes {
280 | if let nodeView = _nodeViews[x, y] {
281 | if nodeView.node.parent != nil { nodeView.setNeedsDisplay() }
282 | }
283 | }
284 | }
285 |
286 | }
287 |
--------------------------------------------------------------------------------
/Pathfinder-Demo/Images.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "scale" : "1x",
5 | "idiom" : "ipad",
6 | "filename" : "Icon-40.png",
7 | "size" : "40x40"
8 | },
9 | {
10 | "scale" : "2x",
11 | "idiom" : "ipad",
12 | "filename" : "Icon-40@2x.png",
13 | "size" : "40x40"
14 | },
15 | {
16 | "scale" : "2x",
17 | "idiom" : "iphone",
18 | "filename" : "Icon-60@2x.png",
19 | "size" : "60x60"
20 | },
21 | {
22 | "scale" : "1x",
23 | "idiom" : "ipad",
24 | "filename" : "Icon-72.png",
25 | "size" : "72x72"
26 | },
27 | {
28 | "scale" : "2x",
29 | "idiom" : "ipad",
30 | "filename" : "Icon-72@2x.png",
31 | "size" : "72x72"
32 | },
33 | {
34 | "scale" : "1x",
35 | "idiom" : "ipad",
36 | "filename" : "Icon-76.png",
37 | "size" : "76x76"
38 | },
39 | {
40 | "scale" : "2x",
41 | "idiom" : "ipad",
42 | "filename" : "Icon-76@2x.png",
43 | "size" : "76x76"
44 | },
45 | {
46 | "scale" : "1x",
47 | "idiom" : "ipad",
48 | "filename" : "Icon-Small-50.png",
49 | "size" : "50x50"
50 | },
51 | {
52 | "scale" : "2x",
53 | "idiom" : "ipad",
54 | "filename" : "Icon-Small-50@2x.png",
55 | "size" : "50x50"
56 | },
57 | {
58 | "scale" : "1x",
59 | "idiom" : "iphone",
60 | "filename" : "Icon-Small.png",
61 | "size" : "29x29"
62 | },
63 | {
64 | "scale" : "2x",
65 | "idiom" : "iphone",
66 | "filename" : "Icon-Small@2x.png",
67 | "size" : "29x29"
68 | },
69 | {
70 | "scale" : "1x",
71 | "idiom" : "iphone",
72 | "filename" : "Icon.png",
73 | "size" : "57x57"
74 | },
75 | {
76 | "scale" : "2x",
77 | "idiom" : "iphone",
78 | "filename" : "Icon@2x.png",
79 | "size" : "57x57"
80 | },
81 | {
82 | "scale" : "3x",
83 | "idiom" : "iphone",
84 | "filename" : "Icon-Small@3x.png",
85 | "size" : "29x29"
86 | },
87 | {
88 | "scale" : "3x",
89 | "idiom" : "iphone",
90 | "filename" : "Icon-40@3x.png",
91 | "size" : "40x40"
92 | },
93 | {
94 | "scale" : "3x",
95 | "idiom" : "iphone",
96 | "filename" : "Icon-60@3x.png",
97 | "size" : "60x60"
98 | },
99 | {
100 | "scale" : "2x",
101 | "idiom" : "iphone",
102 | "filename" : "Icon-40@2x.png",
103 | "size" : "40x40"
104 | },
105 | {
106 | "scale" : "1x",
107 | "idiom" : "ipad",
108 | "filename" : "Icon-Small.png",
109 | "size" : "29x29"
110 | },
111 | {
112 | "scale" : "2x",
113 | "idiom" : "ipad",
114 | "filename" : "Icon-Small@2x.png",
115 | "size" : "29x29"
116 | },
117 | {
118 | "scale" : "2x",
119 | "idiom" : "ipad",
120 | "filename" : "Icon-83.5@2x.png",
121 | "size" : "83.5x83.5"
122 | },
123 | {
124 | "scale" : "2x",
125 | "idiom" : "iphone",
126 | "filename" : "NotificationIcon@2x.png",
127 | "size" : "20x20"
128 | },
129 | {
130 | "scale" : "3x",
131 | "idiom" : "iphone",
132 | "filename" : "NotificationIcon@3x.png",
133 | "size" : "20x20"
134 | },
135 | {
136 | "scale" : "1x",
137 | "idiom" : "ipad",
138 | "filename" : "NotificationIcon~ipad.png",
139 | "size" : "20x20"
140 | },
141 | {
142 | "scale" : "2x",
143 | "idiom" : "ipad",
144 | "filename" : "NotificationIcon~ipad@2x.png",
145 | "size" : "20x20"
146 | },
147 | {
148 | "scale" : "1x",
149 | "idiom" : "ios-marketing",
150 | "filename" : "ios-marketing.png",
151 | "size" : "1024x1024"
152 | }
153 | ],
154 | "info" : {
155 | "version" : 1,
156 | "author" : "xcode"
157 | }
158 | }
--------------------------------------------------------------------------------
/Pathfinder-Demo/Images.xcassets/AppIcon.appiconset/Icon-40.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iluuu1994/Pathfinder/07f2940a4a300313256acb22cd69e0a2747eac42/Pathfinder-Demo/Images.xcassets/AppIcon.appiconset/Icon-40.png
--------------------------------------------------------------------------------
/Pathfinder-Demo/Images.xcassets/AppIcon.appiconset/Icon-40@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iluuu1994/Pathfinder/07f2940a4a300313256acb22cd69e0a2747eac42/Pathfinder-Demo/Images.xcassets/AppIcon.appiconset/Icon-40@2x.png
--------------------------------------------------------------------------------
/Pathfinder-Demo/Images.xcassets/AppIcon.appiconset/Icon-40@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iluuu1994/Pathfinder/07f2940a4a300313256acb22cd69e0a2747eac42/Pathfinder-Demo/Images.xcassets/AppIcon.appiconset/Icon-40@3x.png
--------------------------------------------------------------------------------
/Pathfinder-Demo/Images.xcassets/AppIcon.appiconset/Icon-60@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iluuu1994/Pathfinder/07f2940a4a300313256acb22cd69e0a2747eac42/Pathfinder-Demo/Images.xcassets/AppIcon.appiconset/Icon-60@2x.png
--------------------------------------------------------------------------------
/Pathfinder-Demo/Images.xcassets/AppIcon.appiconset/Icon-60@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iluuu1994/Pathfinder/07f2940a4a300313256acb22cd69e0a2747eac42/Pathfinder-Demo/Images.xcassets/AppIcon.appiconset/Icon-60@3x.png
--------------------------------------------------------------------------------
/Pathfinder-Demo/Images.xcassets/AppIcon.appiconset/Icon-72.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iluuu1994/Pathfinder/07f2940a4a300313256acb22cd69e0a2747eac42/Pathfinder-Demo/Images.xcassets/AppIcon.appiconset/Icon-72.png
--------------------------------------------------------------------------------
/Pathfinder-Demo/Images.xcassets/AppIcon.appiconset/Icon-72@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iluuu1994/Pathfinder/07f2940a4a300313256acb22cd69e0a2747eac42/Pathfinder-Demo/Images.xcassets/AppIcon.appiconset/Icon-72@2x.png
--------------------------------------------------------------------------------
/Pathfinder-Demo/Images.xcassets/AppIcon.appiconset/Icon-76.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iluuu1994/Pathfinder/07f2940a4a300313256acb22cd69e0a2747eac42/Pathfinder-Demo/Images.xcassets/AppIcon.appiconset/Icon-76.png
--------------------------------------------------------------------------------
/Pathfinder-Demo/Images.xcassets/AppIcon.appiconset/Icon-76@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iluuu1994/Pathfinder/07f2940a4a300313256acb22cd69e0a2747eac42/Pathfinder-Demo/Images.xcassets/AppIcon.appiconset/Icon-76@2x.png
--------------------------------------------------------------------------------
/Pathfinder-Demo/Images.xcassets/AppIcon.appiconset/Icon-83.5@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iluuu1994/Pathfinder/07f2940a4a300313256acb22cd69e0a2747eac42/Pathfinder-Demo/Images.xcassets/AppIcon.appiconset/Icon-83.5@2x.png
--------------------------------------------------------------------------------
/Pathfinder-Demo/Images.xcassets/AppIcon.appiconset/Icon-Small-50.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iluuu1994/Pathfinder/07f2940a4a300313256acb22cd69e0a2747eac42/Pathfinder-Demo/Images.xcassets/AppIcon.appiconset/Icon-Small-50.png
--------------------------------------------------------------------------------
/Pathfinder-Demo/Images.xcassets/AppIcon.appiconset/Icon-Small-50@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iluuu1994/Pathfinder/07f2940a4a300313256acb22cd69e0a2747eac42/Pathfinder-Demo/Images.xcassets/AppIcon.appiconset/Icon-Small-50@2x.png
--------------------------------------------------------------------------------
/Pathfinder-Demo/Images.xcassets/AppIcon.appiconset/Icon-Small.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iluuu1994/Pathfinder/07f2940a4a300313256acb22cd69e0a2747eac42/Pathfinder-Demo/Images.xcassets/AppIcon.appiconset/Icon-Small.png
--------------------------------------------------------------------------------
/Pathfinder-Demo/Images.xcassets/AppIcon.appiconset/Icon-Small@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iluuu1994/Pathfinder/07f2940a4a300313256acb22cd69e0a2747eac42/Pathfinder-Demo/Images.xcassets/AppIcon.appiconset/Icon-Small@2x.png
--------------------------------------------------------------------------------
/Pathfinder-Demo/Images.xcassets/AppIcon.appiconset/Icon-Small@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iluuu1994/Pathfinder/07f2940a4a300313256acb22cd69e0a2747eac42/Pathfinder-Demo/Images.xcassets/AppIcon.appiconset/Icon-Small@3x.png
--------------------------------------------------------------------------------
/Pathfinder-Demo/Images.xcassets/AppIcon.appiconset/Icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iluuu1994/Pathfinder/07f2940a4a300313256acb22cd69e0a2747eac42/Pathfinder-Demo/Images.xcassets/AppIcon.appiconset/Icon.png
--------------------------------------------------------------------------------
/Pathfinder-Demo/Images.xcassets/AppIcon.appiconset/Icon@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iluuu1994/Pathfinder/07f2940a4a300313256acb22cd69e0a2747eac42/Pathfinder-Demo/Images.xcassets/AppIcon.appiconset/Icon@2x.png
--------------------------------------------------------------------------------
/Pathfinder-Demo/Images.xcassets/AppIcon.appiconset/NotificationIcon@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iluuu1994/Pathfinder/07f2940a4a300313256acb22cd69e0a2747eac42/Pathfinder-Demo/Images.xcassets/AppIcon.appiconset/NotificationIcon@2x.png
--------------------------------------------------------------------------------
/Pathfinder-Demo/Images.xcassets/AppIcon.appiconset/NotificationIcon@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iluuu1994/Pathfinder/07f2940a4a300313256acb22cd69e0a2747eac42/Pathfinder-Demo/Images.xcassets/AppIcon.appiconset/NotificationIcon@3x.png
--------------------------------------------------------------------------------
/Pathfinder-Demo/Images.xcassets/AppIcon.appiconset/NotificationIcon~ipad.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iluuu1994/Pathfinder/07f2940a4a300313256acb22cd69e0a2747eac42/Pathfinder-Demo/Images.xcassets/AppIcon.appiconset/NotificationIcon~ipad.png
--------------------------------------------------------------------------------
/Pathfinder-Demo/Images.xcassets/AppIcon.appiconset/NotificationIcon~ipad@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iluuu1994/Pathfinder/07f2940a4a300313256acb22cd69e0a2747eac42/Pathfinder-Demo/Images.xcassets/AppIcon.appiconset/NotificationIcon~ipad@2x.png
--------------------------------------------------------------------------------
/Pathfinder-Demo/Images.xcassets/AppIcon.appiconset/ios-marketing.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iluuu1994/Pathfinder/07f2940a4a300313256acb22cd69e0a2747eac42/Pathfinder-Demo/Images.xcassets/AppIcon.appiconset/ios-marketing.png
--------------------------------------------------------------------------------
/Pathfinder-Demo/Images.xcassets/LaunchImage.launchimage/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "orientation" : "portrait",
5 | "idiom" : "iphone",
6 | "extent" : "full-screen",
7 | "minimum-system-version" : "7.0",
8 | "scale" : "2x"
9 | },
10 | {
11 | "orientation" : "portrait",
12 | "idiom" : "iphone",
13 | "subtype" : "retina4",
14 | "extent" : "full-screen",
15 | "minimum-system-version" : "7.0",
16 | "scale" : "2x"
17 | }
18 | ],
19 | "info" : {
20 | "version" : 1,
21 | "author" : "xcode"
22 | }
23 | }
--------------------------------------------------------------------------------
/Pathfinder-Demo/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | APPL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1
23 | LSRequiresIPhoneOS
24 |
25 | UIMainStoryboardFile
26 | Main
27 | UIRequiredDeviceCapabilities
28 |
29 | armv7
30 |
31 | UISupportedInterfaceOrientations
32 |
33 | UIInterfaceOrientationPortrait
34 | UIInterfaceOrientationLandscapeLeft
35 | UIInterfaceOrientationLandscapeRight
36 |
37 |
38 |
39 |
--------------------------------------------------------------------------------
/Pathfinder-Demo/NodeView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // NodeView.swift
3 | // Pathfinder
4 | //
5 | // Created by Ilija Tovilo on 16/08/14.
6 | // Copyright (c) 2014 Ilija Tovilo
7 | //
8 | // Permission is hereby granted, free of charge, to any person obtaining a copy
9 | // of this software and associated documentation files (the "Software"), to deal
10 | // in the Software without restriction, including without limitation the rights
11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | // copies of the Software, and to permit persons to whom the Software is
13 | // furnished to do so, subject to the following conditions:
14 | //
15 | // The above copyright notice and this permission notice shall be included in all
16 | // copies or substantial portions of the Software.
17 | //
18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 | // SOFTWARE.
25 |
26 | import UIKit
27 | import Pathfinder
28 |
29 | public class NodeView: UIView {
30 |
31 | public enum PathType {
32 | case Empty, Start, End, Obstacle
33 | }
34 |
35 | public let node: Node
36 | private var _pathType: PathType = .Empty
37 |
38 | private var _partOfPath: Bool = false
39 | public var partOfPath: Bool {
40 | get {
41 | return _partOfPath
42 | }
43 | set(newValue) {
44 | _partOfPath = newValue
45 | setNeedsDisplay()
46 | }
47 | }
48 |
49 | public var type: PathType {
50 | get {
51 | return _pathType
52 | }
53 | set(newPathType) {
54 | _pathType = newPathType
55 |
56 | switch _pathType {
57 | case .Obstacle:
58 | node.accessible = false
59 | default:
60 | node.accessible = true
61 | }
62 |
63 | setNeedsDisplay()
64 | }
65 | }
66 |
67 | private var _color: UIColor {
68 | switch _pathType {
69 | case .Empty:
70 | return !partOfPath ? (node.parent == nil ? UIColor(white: 1.0, alpha: 1.0) : // Default
71 | UIColor(red: 0.83, green: 0.93, blue: 1.0, alpha: 1.0)) : // Open List
72 | UIColor(red: 0.43, green: 0.7, blue: 0.9, alpha: 1.0) // Path
73 | case .Obstacle:
74 | return UIColor(white: 0.4, alpha: 1.0)
75 | case .Start:
76 | return UIColor(red: 0.75, green: 0.23, blue: 0.19, alpha: 1.0)
77 | case .End:
78 | return UIColor(red: 0.22, green: 0.8, blue: 0.46, alpha: 1.0)
79 | }
80 | }
81 |
82 | init(frame: CGRect, node: Node) {
83 | self.node = node
84 | super.init(frame: frame)
85 | }
86 |
87 | // Compiler, shut up!
88 | required public init(coder aDecoder: NSCoder) {
89 | self.node = Node(coordinates: Coordinates2D(x: 0, y: 0))
90 | super.init(coder: aDecoder)!
91 | }
92 |
93 | override public func draw(_ rect: CGRect) {
94 | _color.set()
95 | UIRectFill(rect)
96 |
97 | UIColor(white: 0.0, alpha: 0.1).setStroke()
98 | UIBezierPath(rect: bounds).stroke()
99 | }
100 | }
101 |
102 |
--------------------------------------------------------------------------------
/Pathfinder-Demo/Pathfinder-Demo-Bridging-Header.h:
--------------------------------------------------------------------------------
1 | //
2 | // Use this file to import your target's public headers that you would like to expose to Swift.
3 | //
4 |
5 |
6 |
--------------------------------------------------------------------------------
/Pathfinder-Demo/ViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ViewController.swift
3 | // Pathfinder-Demo
4 | //
5 | // Created by Ilija Tovilo on 15/08/14.
6 | // Copyright (c) 2014 Ilija Tovilo
7 | //
8 | // Permission is hereby granted, free of charge, to any person obtaining a copy
9 | // of this software and associated documentation files (the "Software"), to deal
10 | // in the Software without restriction, including without limitation the rights
11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | // copies of the Software, and to permit persons to whom the Software is
13 | // furnished to do so, subject to the following conditions:
14 | //
15 | // The above copyright notice and this permission notice shall be included in all
16 | // copies or substantial portions of the Software.
17 | //
18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 | // SOFTWARE.
25 |
26 | import UIKit
27 |
28 | class ViewController: UIViewController {
29 | @IBOutlet weak var gridView: GridView!
30 |
31 | @IBAction func findPath(_ sender: Any) {
32 | gridView.findPath()
33 | }
34 |
35 | @IBAction func reset(_ sender: Any) {
36 | gridView.reset()
37 | }
38 |
39 | override func viewDidLayoutSubviews() {
40 | super.viewDidLayoutSubviews()
41 | gridView.viewControllerDidLayoutSubviews()
42 | }
43 | }
44 |
45 |
--------------------------------------------------------------------------------
/Pathfinder.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 46;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | 9119C515199D962A001DB154 /* Pathfinder.h in Headers */ = {isa = PBXBuildFile; fileRef = 9119C514199D962A001DB154 /* Pathfinder.h */; settings = {ATTRIBUTES = (Public, ); }; };
11 | 9119C529199D9633001DB154 /* Node.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9119C528199D9633001DB154 /* Node.swift */; };
12 | 9119C52B199D9663001DB154 /* Map.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9119C52A199D9663001DB154 /* Map.swift */; };
13 | 911CD2A5199FF26A00EA7BAD /* Helpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 911CD2A4199FF26A00EA7BAD /* Helpers.swift */; };
14 | 911CD2A7199FFCA200EA7BAD /* NodeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 911CD2A6199FFCA200EA7BAD /* NodeView.swift */; };
15 | 911CD2AD19A00B1F00EA7BAD /* AStarAlgorithm.swift in Sources */ = {isa = PBXBuildFile; fileRef = 911CD2AC19A00B1F00EA7BAD /* AStarAlgorithm.swift */; };
16 | 914147E3199F809C009DB333 /* Coordinates.swift in Sources */ = {isa = PBXBuildFile; fileRef = 914147E2199F809C009DB333 /* Coordinates.swift */; };
17 | 91761659199E220300253001 /* Algorithm.swift in Sources */ = {isa = PBXBuildFile; fileRef = 91761658199E220300253001 /* Algorithm.swift */; };
18 | 91761665199E926500253001 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 91761664199E926500253001 /* AppDelegate.swift */; };
19 | 91761667199E926500253001 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 91761666199E926500253001 /* ViewController.swift */; };
20 | 9176166A199E926500253001 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 91761668199E926500253001 /* Main.storyboard */; };
21 | 9176166C199E926500253001 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 9176166B199E926500253001 /* Images.xcassets */; };
22 | 9176167F199E929B00253001 /* Pathfinder.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9119C50F199D962A001DB154 /* Pathfinder.framework */; };
23 | 91761681199E972300253001 /* GridView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 91761680199E972300253001 /* GridView.swift */; };
24 | 91761683199E98AD00253001 /* Grid.swift in Sources */ = {isa = PBXBuildFile; fileRef = 91761682199E98AD00253001 /* Grid.swift */; };
25 | 91761687199E99FB00253001 /* Matrix.swift in Sources */ = {isa = PBXBuildFile; fileRef = 91761686199E99FB00253001 /* Matrix.swift */; };
26 | 9186EF8C19A0D20D00D1D4FA /* IndexedArray.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9186EF8B19A0D20D00D1D4FA /* IndexedArray.swift */; };
27 | 91DC3B9A19A11AD000FC9732 /* HeuristicFunction.swift in Sources */ = {isa = PBXBuildFile; fileRef = 91DC3B9919A11AD000FC9732 /* HeuristicFunction.swift */; };
28 | /* End PBXBuildFile section */
29 |
30 | /* Begin PBXFileReference section */
31 | 9119C50F199D962A001DB154 /* Pathfinder.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pathfinder.framework; sourceTree = BUILT_PRODUCTS_DIR; };
32 | 9119C513199D962A001DB154 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
33 | 9119C514199D962A001DB154 /* Pathfinder.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Pathfinder.h; sourceTree = ""; };
34 | 9119C528199D9633001DB154 /* Node.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Node.swift; sourceTree = ""; };
35 | 9119C52A199D9663001DB154 /* Map.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Map.swift; sourceTree = ""; };
36 | 911CD2A4199FF26A00EA7BAD /* Helpers.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Helpers.swift; sourceTree = ""; };
37 | 911CD2A6199FFCA200EA7BAD /* NodeView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NodeView.swift; sourceTree = ""; };
38 | 911CD2AC19A00B1F00EA7BAD /* AStarAlgorithm.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AStarAlgorithm.swift; sourceTree = ""; };
39 | 914147E2199F809C009DB333 /* Coordinates.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Coordinates.swift; sourceTree = ""; };
40 | 91761658199E220300253001 /* Algorithm.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Algorithm.swift; sourceTree = ""; };
41 | 91761660199E926500253001 /* Pathfinder-Demo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Pathfinder-Demo.app"; sourceTree = BUILT_PRODUCTS_DIR; };
42 | 91761663199E926500253001 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
43 | 91761664199E926500253001 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; };
44 | 91761666199E926500253001 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; };
45 | 91761669199E926500253001 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; };
46 | 9176166B199E926500253001 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; };
47 | 91761680199E972300253001 /* GridView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GridView.swift; sourceTree = ""; };
48 | 91761682199E98AD00253001 /* Grid.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Grid.swift; sourceTree = ""; };
49 | 91761686199E99FB00253001 /* Matrix.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Matrix.swift; sourceTree = ""; };
50 | 9186EF8B19A0D20D00D1D4FA /* IndexedArray.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = IndexedArray.swift; sourceTree = ""; };
51 | 91DC3B9919A11AD000FC9732 /* HeuristicFunction.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HeuristicFunction.swift; sourceTree = ""; };
52 | 91DC3B9D19A138CE00FC9732 /* Pathfinder-Demo-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Pathfinder-Demo-Bridging-Header.h"; sourceTree = ""; };
53 | /* End PBXFileReference section */
54 |
55 | /* Begin PBXFrameworksBuildPhase section */
56 | 9119C50B199D962A001DB154 /* Frameworks */ = {
57 | isa = PBXFrameworksBuildPhase;
58 | buildActionMask = 2147483647;
59 | files = (
60 | );
61 | runOnlyForDeploymentPostprocessing = 0;
62 | };
63 | 9176165D199E926500253001 /* Frameworks */ = {
64 | isa = PBXFrameworksBuildPhase;
65 | buildActionMask = 2147483647;
66 | files = (
67 | 9176167F199E929B00253001 /* Pathfinder.framework in Frameworks */,
68 | );
69 | runOnlyForDeploymentPostprocessing = 0;
70 | };
71 | /* End PBXFrameworksBuildPhase section */
72 |
73 | /* Begin PBXGroup section */
74 | 9119C505199D962A001DB154 = {
75 | isa = PBXGroup;
76 | children = (
77 | 9119C511199D962A001DB154 /* Pathfinder */,
78 | 91761661199E926500253001 /* Pathfinder-Demo */,
79 | 9119C510199D962A001DB154 /* Products */,
80 | );
81 | sourceTree = "";
82 | };
83 | 9119C510199D962A001DB154 /* Products */ = {
84 | isa = PBXGroup;
85 | children = (
86 | 9119C50F199D962A001DB154 /* Pathfinder.framework */,
87 | 91761660199E926500253001 /* Pathfinder-Demo.app */,
88 | );
89 | name = Products;
90 | sourceTree = "";
91 | };
92 | 9119C511199D962A001DB154 /* Pathfinder */ = {
93 | isa = PBXGroup;
94 | children = (
95 | 9119C514199D962A001DB154 /* Pathfinder.h */,
96 | 91761684199E98C100253001 /* Source */,
97 | 9119C512199D962A001DB154 /* Supporting Files */,
98 | );
99 | path = Pathfinder;
100 | sourceTree = "";
101 | };
102 | 9119C512199D962A001DB154 /* Supporting Files */ = {
103 | isa = PBXGroup;
104 | children = (
105 | 9119C513199D962A001DB154 /* Info.plist */,
106 | );
107 | name = "Supporting Files";
108 | sourceTree = "";
109 | };
110 | 911CD2AA19A00AF700EA7BAD /* Algorithms */ = {
111 | isa = PBXGroup;
112 | children = (
113 | 911CD2AC19A00B1F00EA7BAD /* AStarAlgorithm.swift */,
114 | );
115 | name = Algorithms;
116 | sourceTree = "";
117 | };
118 | 911CD2AB19A00B0600EA7BAD /* Helpers */ = {
119 | isa = PBXGroup;
120 | children = (
121 | 9186EF8B19A0D20D00D1D4FA /* IndexedArray.swift */,
122 | 91761686199E99FB00253001 /* Matrix.swift */,
123 | 911CD2A4199FF26A00EA7BAD /* Helpers.swift */,
124 | );
125 | name = Helpers;
126 | sourceTree = "";
127 | };
128 | 911CD2AE19A00BA900EA7BAD /* Core */ = {
129 | isa = PBXGroup;
130 | children = (
131 | 91761658199E220300253001 /* Algorithm.swift */,
132 | 9119C528199D9633001DB154 /* Node.swift */,
133 | 914147E2199F809C009DB333 /* Coordinates.swift */,
134 | 9119C52A199D9663001DB154 /* Map.swift */,
135 | 91DC3B9919A11AD000FC9732 /* HeuristicFunction.swift */,
136 | );
137 | name = Core;
138 | sourceTree = "";
139 | };
140 | 91761661199E926500253001 /* Pathfinder-Demo */ = {
141 | isa = PBXGroup;
142 | children = (
143 | 91761664199E926500253001 /* AppDelegate.swift */,
144 | 91761680199E972300253001 /* GridView.swift */,
145 | 9176166B199E926500253001 /* Images.xcassets */,
146 | 91761668199E926500253001 /* Main.storyboard */,
147 | 911CD2A6199FFCA200EA7BAD /* NodeView.swift */,
148 | 91761662199E926500253001 /* Supporting Files */,
149 | 91761666199E926500253001 /* ViewController.swift */,
150 | );
151 | path = "Pathfinder-Demo";
152 | sourceTree = "";
153 | };
154 | 91761662199E926500253001 /* Supporting Files */ = {
155 | isa = PBXGroup;
156 | children = (
157 | 91DC3B9D19A138CE00FC9732 /* Pathfinder-Demo-Bridging-Header.h */,
158 | 91761663199E926500253001 /* Info.plist */,
159 | );
160 | name = "Supporting Files";
161 | sourceTree = "";
162 | };
163 | 91761684199E98C100253001 /* Source */ = {
164 | isa = PBXGroup;
165 | children = (
166 | 911CD2AA19A00AF700EA7BAD /* Algorithms */,
167 | 911CD2AE19A00BA900EA7BAD /* Core */,
168 | 91761685199E98C900253001 /* Maps */,
169 | 911CD2AB19A00B0600EA7BAD /* Helpers */,
170 | );
171 | name = Source;
172 | sourceTree = "";
173 | };
174 | 91761685199E98C900253001 /* Maps */ = {
175 | isa = PBXGroup;
176 | children = (
177 | 91761682199E98AD00253001 /* Grid.swift */,
178 | );
179 | name = Maps;
180 | sourceTree = "";
181 | };
182 | /* End PBXGroup section */
183 |
184 | /* Begin PBXHeadersBuildPhase section */
185 | 9119C50C199D962A001DB154 /* Headers */ = {
186 | isa = PBXHeadersBuildPhase;
187 | buildActionMask = 2147483647;
188 | files = (
189 | 9119C515199D962A001DB154 /* Pathfinder.h in Headers */,
190 | );
191 | runOnlyForDeploymentPostprocessing = 0;
192 | };
193 | /* End PBXHeadersBuildPhase section */
194 |
195 | /* Begin PBXNativeTarget section */
196 | 9119C50E199D962A001DB154 /* Pathfinder */ = {
197 | isa = PBXNativeTarget;
198 | buildConfigurationList = 9119C522199D962A001DB154 /* Build configuration list for PBXNativeTarget "Pathfinder" */;
199 | buildPhases = (
200 | 9119C50A199D962A001DB154 /* Sources */,
201 | 9119C50B199D962A001DB154 /* Frameworks */,
202 | 9119C50C199D962A001DB154 /* Headers */,
203 | 9119C50D199D962A001DB154 /* Resources */,
204 | );
205 | buildRules = (
206 | );
207 | dependencies = (
208 | );
209 | name = Pathfinder;
210 | productName = Pathfinder;
211 | productReference = 9119C50F199D962A001DB154 /* Pathfinder.framework */;
212 | productType = "com.apple.product-type.framework";
213 | };
214 | 9176165F199E926500253001 /* Pathfinder-Demo */ = {
215 | isa = PBXNativeTarget;
216 | buildConfigurationList = 91761679199E926500253001 /* Build configuration list for PBXNativeTarget "Pathfinder-Demo" */;
217 | buildPhases = (
218 | 9176165C199E926500253001 /* Sources */,
219 | 9176165D199E926500253001 /* Frameworks */,
220 | 9176165E199E926500253001 /* Resources */,
221 | );
222 | buildRules = (
223 | );
224 | dependencies = (
225 | );
226 | name = "Pathfinder-Demo";
227 | productName = "Pathfinder-Demo";
228 | productReference = 91761660199E926500253001 /* Pathfinder-Demo.app */;
229 | productType = "com.apple.product-type.application";
230 | };
231 | /* End PBXNativeTarget section */
232 |
233 | /* Begin PBXProject section */
234 | 9119C506199D962A001DB154 /* Project object */ = {
235 | isa = PBXProject;
236 | attributes = {
237 | LastUpgradeCheck = 1000;
238 | ORGANIZATIONNAME = "Ilija Tovilo";
239 | TargetAttributes = {
240 | 9119C50E199D962A001DB154 = {
241 | CreatedOnToolsVersion = 6.0;
242 | LastSwiftMigration = 0800;
243 | };
244 | 9176165F199E926500253001 = {
245 | CreatedOnToolsVersion = 6.0;
246 | };
247 | };
248 | };
249 | buildConfigurationList = 9119C509199D962A001DB154 /* Build configuration list for PBXProject "Pathfinder" */;
250 | compatibilityVersion = "Xcode 3.2";
251 | developmentRegion = English;
252 | hasScannedForEncodings = 0;
253 | knownRegions = (
254 | en,
255 | Base,
256 | );
257 | mainGroup = 9119C505199D962A001DB154;
258 | productRefGroup = 9119C510199D962A001DB154 /* Products */;
259 | projectDirPath = "";
260 | projectRoot = "";
261 | targets = (
262 | 9119C50E199D962A001DB154 /* Pathfinder */,
263 | 9176165F199E926500253001 /* Pathfinder-Demo */,
264 | );
265 | };
266 | /* End PBXProject section */
267 |
268 | /* Begin PBXResourcesBuildPhase section */
269 | 9119C50D199D962A001DB154 /* Resources */ = {
270 | isa = PBXResourcesBuildPhase;
271 | buildActionMask = 2147483647;
272 | files = (
273 | );
274 | runOnlyForDeploymentPostprocessing = 0;
275 | };
276 | 9176165E199E926500253001 /* Resources */ = {
277 | isa = PBXResourcesBuildPhase;
278 | buildActionMask = 2147483647;
279 | files = (
280 | 9176166A199E926500253001 /* Main.storyboard in Resources */,
281 | 9176166C199E926500253001 /* Images.xcassets in Resources */,
282 | );
283 | runOnlyForDeploymentPostprocessing = 0;
284 | };
285 | /* End PBXResourcesBuildPhase section */
286 |
287 | /* Begin PBXSourcesBuildPhase section */
288 | 9119C50A199D962A001DB154 /* Sources */ = {
289 | isa = PBXSourcesBuildPhase;
290 | buildActionMask = 2147483647;
291 | files = (
292 | 914147E3199F809C009DB333 /* Coordinates.swift in Sources */,
293 | 9119C52B199D9663001DB154 /* Map.swift in Sources */,
294 | 911CD2AD19A00B1F00EA7BAD /* AStarAlgorithm.swift in Sources */,
295 | 9186EF8C19A0D20D00D1D4FA /* IndexedArray.swift in Sources */,
296 | 91761659199E220300253001 /* Algorithm.swift in Sources */,
297 | 911CD2A5199FF26A00EA7BAD /* Helpers.swift in Sources */,
298 | 91DC3B9A19A11AD000FC9732 /* HeuristicFunction.swift in Sources */,
299 | 91761687199E99FB00253001 /* Matrix.swift in Sources */,
300 | 91761683199E98AD00253001 /* Grid.swift in Sources */,
301 | 9119C529199D9633001DB154 /* Node.swift in Sources */,
302 | );
303 | runOnlyForDeploymentPostprocessing = 0;
304 | };
305 | 9176165C199E926500253001 /* Sources */ = {
306 | isa = PBXSourcesBuildPhase;
307 | buildActionMask = 2147483647;
308 | files = (
309 | 91761667199E926500253001 /* ViewController.swift in Sources */,
310 | 91761681199E972300253001 /* GridView.swift in Sources */,
311 | 911CD2A7199FFCA200EA7BAD /* NodeView.swift in Sources */,
312 | 91761665199E926500253001 /* AppDelegate.swift in Sources */,
313 | );
314 | runOnlyForDeploymentPostprocessing = 0;
315 | };
316 | /* End PBXSourcesBuildPhase section */
317 |
318 | /* Begin PBXVariantGroup section */
319 | 91761668199E926500253001 /* Main.storyboard */ = {
320 | isa = PBXVariantGroup;
321 | children = (
322 | 91761669199E926500253001 /* Base */,
323 | );
324 | name = Main.storyboard;
325 | sourceTree = "";
326 | };
327 | /* End PBXVariantGroup section */
328 |
329 | /* Begin XCBuildConfiguration section */
330 | 9119C520199D962A001DB154 /* Debug */ = {
331 | isa = XCBuildConfiguration;
332 | buildSettings = {
333 | ALWAYS_SEARCH_USER_PATHS = NO;
334 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
335 | CLANG_CXX_LIBRARY = "libc++";
336 | CLANG_ENABLE_MODULES = YES;
337 | CLANG_ENABLE_OBJC_ARC = YES;
338 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
339 | CLANG_WARN_BOOL_CONVERSION = YES;
340 | CLANG_WARN_COMMA = YES;
341 | CLANG_WARN_CONSTANT_CONVERSION = YES;
342 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
343 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
344 | CLANG_WARN_EMPTY_BODY = YES;
345 | CLANG_WARN_ENUM_CONVERSION = YES;
346 | CLANG_WARN_INFINITE_RECURSION = YES;
347 | CLANG_WARN_INT_CONVERSION = YES;
348 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
349 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
350 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
351 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
352 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
353 | CLANG_WARN_STRICT_PROTOTYPES = YES;
354 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
355 | CLANG_WARN_UNREACHABLE_CODE = YES;
356 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
357 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
358 | COPY_PHASE_STRIP = NO;
359 | CURRENT_PROJECT_VERSION = 1;
360 | ENABLE_STRICT_OBJC_MSGSEND = YES;
361 | ENABLE_TESTABILITY = YES;
362 | GCC_C_LANGUAGE_STANDARD = gnu99;
363 | GCC_DYNAMIC_NO_PIC = NO;
364 | GCC_NO_COMMON_BLOCKS = YES;
365 | GCC_OPTIMIZATION_LEVEL = 0;
366 | GCC_PREPROCESSOR_DEFINITIONS = (
367 | "DEBUG=1",
368 | "$(inherited)",
369 | );
370 | GCC_SYMBOLS_PRIVATE_EXTERN = NO;
371 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
372 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
373 | GCC_WARN_UNDECLARED_SELECTOR = YES;
374 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
375 | GCC_WARN_UNUSED_FUNCTION = YES;
376 | GCC_WARN_UNUSED_VARIABLE = YES;
377 | IPHONEOS_DEPLOYMENT_TARGET = 8.0;
378 | MTL_ENABLE_DEBUG_INFO = YES;
379 | ONLY_ACTIVE_ARCH = YES;
380 | SDKROOT = iphoneos;
381 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
382 | TARGETED_DEVICE_FAMILY = "1,2";
383 | VERSIONING_SYSTEM = "apple-generic";
384 | VERSION_INFO_PREFIX = "";
385 | };
386 | name = Debug;
387 | };
388 | 9119C521199D962A001DB154 /* Release */ = {
389 | isa = XCBuildConfiguration;
390 | buildSettings = {
391 | ALWAYS_SEARCH_USER_PATHS = NO;
392 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
393 | CLANG_CXX_LIBRARY = "libc++";
394 | CLANG_ENABLE_MODULES = YES;
395 | CLANG_ENABLE_OBJC_ARC = YES;
396 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
397 | CLANG_WARN_BOOL_CONVERSION = YES;
398 | CLANG_WARN_COMMA = YES;
399 | CLANG_WARN_CONSTANT_CONVERSION = YES;
400 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
401 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
402 | CLANG_WARN_EMPTY_BODY = YES;
403 | CLANG_WARN_ENUM_CONVERSION = YES;
404 | CLANG_WARN_INFINITE_RECURSION = YES;
405 | CLANG_WARN_INT_CONVERSION = YES;
406 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
407 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
408 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
409 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
410 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
411 | CLANG_WARN_STRICT_PROTOTYPES = YES;
412 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
413 | CLANG_WARN_UNREACHABLE_CODE = YES;
414 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
415 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
416 | COPY_PHASE_STRIP = YES;
417 | CURRENT_PROJECT_VERSION = 1;
418 | ENABLE_NS_ASSERTIONS = NO;
419 | ENABLE_STRICT_OBJC_MSGSEND = YES;
420 | GCC_C_LANGUAGE_STANDARD = gnu99;
421 | GCC_NO_COMMON_BLOCKS = YES;
422 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
423 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
424 | GCC_WARN_UNDECLARED_SELECTOR = YES;
425 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
426 | GCC_WARN_UNUSED_FUNCTION = YES;
427 | GCC_WARN_UNUSED_VARIABLE = YES;
428 | IPHONEOS_DEPLOYMENT_TARGET = 8.0;
429 | MTL_ENABLE_DEBUG_INFO = NO;
430 | SDKROOT = iphoneos;
431 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
432 | TARGETED_DEVICE_FAMILY = "1,2";
433 | VALIDATE_PRODUCT = YES;
434 | VERSIONING_SYSTEM = "apple-generic";
435 | VERSION_INFO_PREFIX = "";
436 | };
437 | name = Release;
438 | };
439 | 9119C523199D962A001DB154 /* Debug */ = {
440 | isa = XCBuildConfiguration;
441 | buildSettings = {
442 | CLANG_ENABLE_MODULES = YES;
443 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
444 | DEFINES_MODULE = YES;
445 | DYLIB_COMPATIBILITY_VERSION = 1;
446 | DYLIB_CURRENT_VERSION = 1;
447 | DYLIB_INSTALL_NAME_BASE = "@rpath";
448 | INFOPLIST_FILE = Pathfinder/Info.plist;
449 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
450 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
451 | PRODUCT_BUNDLE_IDENTIFIER = "ch.ilijatovilo.$(PRODUCT_NAME:rfc1034identifier)";
452 | PRODUCT_NAME = "$(TARGET_NAME)";
453 | SKIP_INSTALL = YES;
454 | SWIFT_VERSION = 4.2;
455 | };
456 | name = Debug;
457 | };
458 | 9119C524199D962A001DB154 /* Release */ = {
459 | isa = XCBuildConfiguration;
460 | buildSettings = {
461 | CLANG_ENABLE_MODULES = YES;
462 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
463 | DEFINES_MODULE = YES;
464 | DYLIB_COMPATIBILITY_VERSION = 1;
465 | DYLIB_CURRENT_VERSION = 1;
466 | DYLIB_INSTALL_NAME_BASE = "@rpath";
467 | INFOPLIST_FILE = Pathfinder/Info.plist;
468 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
469 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
470 | PRODUCT_BUNDLE_IDENTIFIER = "ch.ilijatovilo.$(PRODUCT_NAME:rfc1034identifier)";
471 | PRODUCT_NAME = "$(TARGET_NAME)";
472 | SKIP_INSTALL = YES;
473 | SWIFT_VERSION = 4.2;
474 | };
475 | name = Release;
476 | };
477 | 9176167A199E926500253001 /* Debug */ = {
478 | isa = XCBuildConfiguration;
479 | buildSettings = {
480 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
481 | ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage;
482 | CLANG_ENABLE_MODULES = YES;
483 | GCC_PREPROCESSOR_DEFINITIONS = (
484 | "DEBUG=1",
485 | "$(inherited)",
486 | );
487 | INFOPLIST_FILE = "Pathfinder-Demo/Info.plist";
488 | IPHONEOS_DEPLOYMENT_TARGET = 9.0;
489 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
490 | PRODUCT_BUNDLE_IDENTIFIER = "ch.ilijatovilo.$(PRODUCT_NAME:rfc1034identifier)";
491 | PRODUCT_NAME = "$(TARGET_NAME)";
492 | SWIFT_OBJC_BRIDGING_HEADER = "Pathfinder-Demo/Pathfinder-Demo-Bridging-Header.h";
493 | SWIFT_VERSION = 4.2;
494 | };
495 | name = Debug;
496 | };
497 | 9176167B199E926500253001 /* Release */ = {
498 | isa = XCBuildConfiguration;
499 | buildSettings = {
500 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
501 | ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage;
502 | CLANG_ENABLE_MODULES = YES;
503 | INFOPLIST_FILE = "Pathfinder-Demo/Info.plist";
504 | IPHONEOS_DEPLOYMENT_TARGET = 9.0;
505 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
506 | PRODUCT_BUNDLE_IDENTIFIER = "ch.ilijatovilo.$(PRODUCT_NAME:rfc1034identifier)";
507 | PRODUCT_NAME = "$(TARGET_NAME)";
508 | SWIFT_OBJC_BRIDGING_HEADER = "Pathfinder-Demo/Pathfinder-Demo-Bridging-Header.h";
509 | SWIFT_VERSION = 4.2;
510 | };
511 | name = Release;
512 | };
513 | /* End XCBuildConfiguration section */
514 |
515 | /* Begin XCConfigurationList section */
516 | 9119C509199D962A001DB154 /* Build configuration list for PBXProject "Pathfinder" */ = {
517 | isa = XCConfigurationList;
518 | buildConfigurations = (
519 | 9119C520199D962A001DB154 /* Debug */,
520 | 9119C521199D962A001DB154 /* Release */,
521 | );
522 | defaultConfigurationIsVisible = 0;
523 | defaultConfigurationName = Release;
524 | };
525 | 9119C522199D962A001DB154 /* Build configuration list for PBXNativeTarget "Pathfinder" */ = {
526 | isa = XCConfigurationList;
527 | buildConfigurations = (
528 | 9119C523199D962A001DB154 /* Debug */,
529 | 9119C524199D962A001DB154 /* Release */,
530 | );
531 | defaultConfigurationIsVisible = 0;
532 | defaultConfigurationName = Release;
533 | };
534 | 91761679199E926500253001 /* Build configuration list for PBXNativeTarget "Pathfinder-Demo" */ = {
535 | isa = XCConfigurationList;
536 | buildConfigurations = (
537 | 9176167A199E926500253001 /* Debug */,
538 | 9176167B199E926500253001 /* Release */,
539 | );
540 | defaultConfigurationIsVisible = 0;
541 | defaultConfigurationName = Release;
542 | };
543 | /* End XCConfigurationList section */
544 | };
545 | rootObject = 9119C506199D962A001DB154 /* Project object */;
546 | }
547 |
--------------------------------------------------------------------------------
/Pathfinder.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/Pathfinder.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/Pathfinder.xcodeproj/xcuserdata/ilijatovilo.xcuserdatad/xcschemes/Pathfinder-Demo.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
32 |
33 |
39 |
40 |
41 |
42 |
51 |
52 |
58 |
59 |
60 |
61 |
62 |
63 |
69 |
70 |
76 |
77 |
78 |
79 |
81 |
82 |
85 |
86 |
87 |
--------------------------------------------------------------------------------
/Pathfinder.xcodeproj/xcuserdata/ilijatovilo.xcuserdatad/xcschemes/Pathfinder.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
32 |
33 |
42 |
43 |
49 |
50 |
51 |
52 |
53 |
54 |
60 |
61 |
67 |
68 |
69 |
70 |
72 |
73 |
76 |
77 |
78 |
--------------------------------------------------------------------------------
/Pathfinder.xcodeproj/xcuserdata/ilijatovilo.xcuserdatad/xcschemes/PathfinderTests.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
33 |
39 |
40 |
41 |
42 |
43 |
49 |
50 |
51 |
52 |
61 |
62 |
68 |
69 |
70 |
71 |
72 |
73 |
79 |
80 |
86 |
87 |
88 |
89 |
91 |
92 |
95 |
96 |
97 |
--------------------------------------------------------------------------------
/Pathfinder.xcodeproj/xcuserdata/ilijatovilo.xcuserdatad/xcschemes/xcschememanagement.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | SchemeUserState
6 |
7 | Pathfinder-Demo.xcscheme
8 |
9 | orderHint
10 | 2
11 |
12 | Pathfinder.xcscheme
13 |
14 | orderHint
15 | 0
16 |
17 | PathfinderTests.xcscheme
18 |
19 | orderHint
20 | 1
21 |
22 |
23 | SuppressBuildableAutocreation
24 |
25 | 9119C50E199D962A001DB154
26 |
27 | primary
28 |
29 |
30 | 9119C519199D962A001DB154
31 |
32 | primary
33 |
34 |
35 | 9176165F199E926500253001
36 |
37 | primary
38 |
39 |
40 | 91761670199E926500253001
41 |
42 | primary
43 |
44 |
45 |
46 |
47 |
48 |
--------------------------------------------------------------------------------
/Pathfinder/AStarAlgorithm.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AStarAlgorithm.swift
3 | // Pathfinder
4 | //
5 | // Created by Ilija Tovilo on 16/08/14.
6 | // Copyright (c) 2014 Ilija Tovilo
7 | //
8 | // Permission is hereby granted, free of charge, to any person obtaining a copy
9 | // of this software and associated documentation files (the "Software"), to deal
10 | // in the Software without restriction, including without limitation the rights
11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | // copies of the Software, and to permit persons to whom the Software is
13 | // furnished to do so, subject to the following conditions:
14 | //
15 | // The above copyright notice and this permission notice shall be included in all
16 | // copies or substantial portions of the Software.
17 | //
18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 | // SOFTWARE.
25 |
26 | import Foundation
27 |
28 | /// AStarAlgorithm is a class that implements the A* Algorithm for pathfinding
29 | /// http://en.wikipedia.org/wiki/A*_search_algorithm
30 | open class AStarAlgorithm: Algorithm {
31 |
32 | /// Finds the path from point A to B in any Map
33 | open class func findPathInMap(_ map: Map, startNode: Node, endNode: Node) -> [Node] {
34 | // var openList: [Node] = [startNode]
35 | let openList = IndexedArray(extractIndex: { (node) in return node.fValue })
36 | openList.add(startNode)
37 |
38 | // Add the neighbours of the start node to the open list to start the iteration process
39 | while let currentNode = openList.array.first {
40 | currentNode.closed = true
41 | openList.removeAtIndex(0)
42 |
43 | // Check if we reached the end node
44 | if currentNode == endNode {
45 | return backtracePath(endNode)
46 | }
47 |
48 | // Returns the neighbours of the node
49 | let validMoves = map.validMoves(currentNode)
50 |
51 | // Check each neighbour and add it to the open list
52 | for neighbour in validMoves {
53 | // If we can't access the tile we have to skip it
54 | if !neighbour.accessible { continue }
55 | // Calculate the move cost
56 | let moveCost = map.moveCostForNode(currentNode, toNode: neighbour)
57 | // We don't check the node if it's in the closed list
58 | if neighbour.closed && (currentNode.gValue + moveCost) >= neighbour.gValue {
59 | continue
60 | }
61 |
62 | if neighbour.opened {
63 | // The node was already added to the open list
64 | // We need to check if we have to re-parent it
65 | neighbour.parent = currentNode
66 | neighbour.gValue = currentNode.gValue + moveCost
67 |
68 | if !neighbour.closed {
69 | // Re-add it the the open list so it's sorted
70 | openList.removeAtIndex(openList.array.index(of:neighbour)!)
71 | openList.add(neighbour)
72 | }
73 | } else {
74 | // Set the parent of the node
75 | neighbour.parent = currentNode
76 |
77 | // Calculate the g value
78 | neighbour.gValue = currentNode.gValue + moveCost
79 |
80 | // Calculate the h value
81 | neighbour.hValue = map.hValueForNode(neighbour, endNode: endNode)
82 |
83 | // Add the new node to the open list
84 | neighbour.opened = true
85 | openList.add(neighbour)
86 | }
87 | }
88 | }
89 |
90 | // If there is no route, we just return an empty array
91 | return []
92 | }
93 |
94 | }
95 |
--------------------------------------------------------------------------------
/Pathfinder/Algorithm.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Algorithm.swift
3 | // Pathfinder
4 | //
5 | // Created by Ilija Tovilo on 15/08/14.
6 | // Copyright (c) 2014 Ilija Tovilo
7 | //
8 | // Permission is hereby granted, free of charge, to any person obtaining a copy
9 | // of this software and associated documentation files (the "Software"), to deal
10 | // in the Software without restriction, including without limitation the rights
11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | // copies of the Software, and to permit persons to whom the Software is
13 | // furnished to do so, subject to the following conditions:
14 | //
15 | // The above copyright notice and this permission notice shall be included in all
16 | // copies or substantial portions of the Software.
17 | //
18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 | // SOFTWARE.
25 |
26 | import Foundation
27 |
28 | /// Algorithm is a protocol that defines the interface for the pathfinding algorithm implementations
29 | public protocol Algorithm: class {
30 |
31 | /// Finds the best path in a map from point A to B
32 | static func findPathInMap(_ map: Map, startNode: Node, endNode: Node) -> [Node]
33 |
34 | }
35 |
--------------------------------------------------------------------------------
/Pathfinder/Coordinates.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Coordinates.swift
3 | // Pathfinder
4 | //
5 | // Created by Ilija Tovilo on 16/08/14.
6 | // Copyright (c) 2014 Ilija Tovilo
7 | //
8 | // Permission is hereby granted, free of charge, to any person obtaining a copy
9 | // of this software and associated documentation files (the "Software"), to deal
10 | // in the Software without restriction, including without limitation the rights
11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | // copies of the Software, and to permit persons to whom the Software is
13 | // furnished to do so, subject to the following conditions:
14 | //
15 | // The above copyright notice and this permission notice shall be included in all
16 | // copies or substantial portions of the Software.
17 | //
18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 | // SOFTWARE.
25 |
26 | import Foundation
27 |
28 | /// Coordinates stores coordinate of any type of coordinate system
29 |
30 | open class Coordinates {
31 |
32 | /// Wraps the coordinates in an array
33 | open func toArray() -> [Int] {
34 | assert(false, "`toArray` must be overridden in the Coordinates subclasses!")
35 | return []
36 | }
37 |
38 |
39 | // ------------------
40 | // MARK: - Hashable -
41 | // ------------------
42 |
43 | // TODO: "Error: Declarations in extensions cannot override yet".
44 | // Move this to the extension once that feature is supported by Swift.
45 | open var hashValue: Int {
46 | return 0
47 | }
48 |
49 | }
50 |
51 |
52 | // ------------------
53 | // MARK: - Hashable -
54 | // ------------------
55 |
56 | extension Coordinates: Hashable {
57 |
58 | }
59 |
60 |
61 | // -------------------
62 | // MARK: - Equatable -
63 | // -------------------
64 |
65 | extension Coordinates: Equatable {}
66 | public func ==(lhs: Coordinates, rhs: Coordinates) -> Bool {
67 | return lhs === rhs
68 | }
69 |
--------------------------------------------------------------------------------
/Pathfinder/Grid.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Grid.swift
3 | // Pathfinder
4 | //
5 | // Created by Ilija Tovilo on 15/08/14.
6 | // Copyright (c) 2014 Ilija Tovilo
7 | //
8 | // Permission is hereby granted, free of charge, to any person obtaining a copy
9 | // of this software and associated documentation files (the "Software"), to deal
10 | // in the Software without restriction, including without limitation the rights
11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | // copies of the Software, and to permit persons to whom the Software is
13 | // furnished to do so, subject to the following conditions:
14 | //
15 | // The above copyright notice and this permission notice shall be included in all
16 | // copies or substantial portions of the Software.
17 | //
18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 | // SOFTWARE.
25 |
26 | import Foundation
27 |
28 |
29 | // ---------------------------------------------------------------------
30 | // MARK: - Coordinates2D -
31 | // ---------------------------------------------------------------------
32 |
33 | /// Entity that stores 2d coordinates
34 | open class Coordinates2D: Coordinates {
35 |
36 | // --------------------
37 | // MARK: - Properties -
38 | // --------------------
39 |
40 | /// The x coordinate
41 | @objc
42 | public let x: Int
43 |
44 | /// The y coordinate
45 | @objc
46 | public let y: Int
47 |
48 | /// Inits the object using both x and y coordinate
49 | @objc
50 | public init(x: Int, y: Int) {
51 | self.x = x
52 | self.y = y
53 | }
54 |
55 |
56 |
57 | // -----------------
58 | // MARK: - Methods -
59 | // -----------------
60 |
61 | override open func toArray() -> [Int] {
62 | return [x, y]
63 | }
64 |
65 |
66 | // ------------------
67 | // MARK: - Hashable -
68 | // ------------------
69 |
70 | // TODO: "Error: Declarations in extensions cannot override yet".
71 | // Move this to the extension once that feature is supported by Swift.
72 | //
73 | // Combines the x and y value as a hash
74 | // http://en.wikipedia.org/wiki/Cantor%5Fpairing%5Ffunction#Cantor_pairing_function
75 | override open var hashValue: Int {
76 | return (x + y)*(x + y + 1)/2 + y
77 | }
78 | }
79 |
80 | // -------------------
81 | // MARK: - Printable -
82 | // -------------------
83 | extension Coordinates2D: CustomStringConvertible {
84 | public var description: String {
85 | return "(\(x),\(y))"
86 | }
87 | }
88 |
89 | // -------------------
90 | // MARK: - Equatable -
91 | // -------------------
92 | public func ==(lhs: Coordinates2D, rhs: Coordinates2D) -> Bool {
93 | return (lhs.x == rhs.x && lhs.y == rhs.y)
94 | }
95 |
96 |
97 |
98 | // ---------------------------------------------------------------------
99 | // MARK: - Grid2D -
100 | // ---------------------------------------------------------------------
101 |
102 | /// Grid is an implementation of a 2d map
103 | open class Grid: Map {
104 |
105 | // --------------------
106 | // MARK: - Properties -
107 | // --------------------
108 |
109 | /// The matrix stores the tiles of the map
110 | fileprivate let _nodes: Matrix
111 |
112 | /// Indicates if the path is allowed to use diagonal moves
113 | // FIXME: Sometimes the path makes weird detours
114 | // FIXME: Allows making directional moves when there are adjacent neighbours
115 | @objc
116 | open var allowsDiagonalMoves = false
117 |
118 | /// Indicates if the path is allowed to use diagonal moves next to a corner
119 | // NOTE: Unimplemented
120 | // TODO: Implement
121 | @objc
122 | open var allowsCuttingCorners = true
123 |
124 |
125 |
126 | // --------------
127 | // MARK: - Init -
128 | // --------------
129 |
130 | /// Init the map using the 2d grid
131 | // TODO: @objc once Matrix is @objc
132 | public init(nodes: Matrix) {
133 | _nodes = nodes
134 | }
135 |
136 |
137 |
138 | // -----------------
139 | // MARK: - Methods -
140 | // -----------------
141 |
142 | /// Returns the valid moves that can be performed from one node to the other
143 | override internal func validMoves(_ node: Node) -> [Node] {
144 | let index = node.coordinates as! Coordinates2D
145 | var moves = [Node]()
146 |
147 | // Those are the delta values from one node coordinate to the other
148 | let adjacentNeighbours = [(1, 0), (0, 1), (-1, 0), (0, -1)]
149 | let diagonalNeighbours = [(1, 1), (-1, 1), (-1, -1), (1, -1)]
150 | let neighbours = allowsDiagonalMoves ? adjacentNeighbours + diagonalNeighbours : adjacentNeighbours
151 |
152 | for (dX, dY) in neighbours {
153 | let x = index.x + dX
154 | let y = index.y + dY
155 |
156 | if x >= 0 && x < _nodes.width {
157 | if y >= 0 && y < _nodes.height {
158 | moves.append(_nodes[x, y])
159 | }
160 | }
161 | }
162 |
163 | return moves
164 | }
165 |
166 | /// Calculates the move cost from one node to one of it's neighbour nodes
167 | override internal func moveCostForNode(_ node: Node, toNode: Node) -> Int {
168 | let index = node.coordinates as! Coordinates2D
169 | let toIndex = toNode.coordinates as! Coordinates2D
170 |
171 | return ((abs(index.x - toIndex.x) > 0 && abs(index.y - toIndex.y) > 0) ? 10 : 14)
172 | }
173 |
174 | /// Calculates the h value of a node
175 | override internal func hValueForNode(_ node: Node, endNode: Node) -> Int {
176 | let coord1 = node.coordinates as! Coordinates2D
177 | let coord2 = endNode.coordinates as! Coordinates2D
178 |
179 | switch heuristicFunction {
180 | case .manhattan:
181 | return (abs(coord1.x - coord2.x) + abs(coord1.y - coord2.y)) * 40
182 | }
183 | }
184 |
185 | }
186 |
--------------------------------------------------------------------------------
/Pathfinder/Helpers.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Helpers.swift
3 | // Pathfinder
4 | //
5 | // Created by Ilija Tovilo on 16/08/14.
6 | // Copyright (c) 2014 Ilija Tovilo
7 | //
8 | // Permission is hereby granted, free of charge, to any person obtaining a copy
9 | // of this software and associated documentation files (the "Software"), to deal
10 | // in the Software without restriction, including without limitation the rights
11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | // copies of the Software, and to permit persons to whom the Software is
13 | // furnished to do so, subject to the following conditions:
14 | //
15 | // The above copyright notice and this permission notice shall be included in all
16 | // copies or substantial portions of the Software.
17 | //
18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 | // SOFTWARE.
25 |
26 | import Foundation
27 |
28 | /// Measures the time of a closure
29 | public func measureTime(_ block: () -> ()) -> Double {
30 | // Record start time
31 | let start = Date()
32 | // Execute the closure
33 | block()
34 | // Record end time
35 | let end = Date()
36 |
37 | // Calculate and return the delta time
38 | return end.timeIntervalSince(start)
39 | }
40 |
41 | /// Build a path from linked nodes
42 | internal func backtracePath(_ endNode: Node) -> [Node] {
43 | var route = [endNode]
44 |
45 | // Recursive lookup of the nodes parent
46 | while let parent = route.first?.parent {
47 | route.insert(parent, at: 0)
48 | }
49 |
50 | return route
51 | }
52 |
--------------------------------------------------------------------------------
/Pathfinder/HeuristicFunction.swift:
--------------------------------------------------------------------------------
1 | //
2 | // HeuristicFunction.swift
3 | // Pathfinder
4 | //
5 | // Created by Ilija Tovilo on 17/08/14.
6 | // Copyright (c) 2014 Ilija Tovilo
7 | //
8 | // Permission is hereby granted, free of charge, to any person obtaining a copy
9 | // of this software and associated documentation files (the "Software"), to deal
10 | // in the Software without restriction, including without limitation the rights
11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | // copies of the Software, and to permit persons to whom the Software is
13 | // furnished to do so, subject to the following conditions:
14 | //
15 | // The above copyright notice and this permission notice shall be included in all
16 | // copies or substantial portions of the Software.
17 | //
18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 | // SOFTWARE.
25 |
26 | import Foundation
27 |
28 | /// Lists the functions that can be used to calculate the heuristic value
29 | public enum HeuristicFunction {
30 | /// dX + dY (+ dZ)
31 | case manhattan
32 | }
33 |
--------------------------------------------------------------------------------
/Pathfinder/IndexedArray.swift:
--------------------------------------------------------------------------------
1 | //
2 | // IndexedArray.swift
3 | // Pathfinder
4 | //
5 | // Created by Ilija Tovilo on 17/08/14.
6 | // Copyright (c) 2014 Ilija Tovilo
7 | //
8 | // Permission is hereby granted, free of charge, to any person obtaining a copy
9 | // of this software and associated documentation files (the "Software"), to deal
10 | // in the Software without restriction, including without limitation the rights
11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | // copies of the Software, and to permit persons to whom the Software is
13 | // furnished to do so, subject to the following conditions:
14 | //
15 | // The above copyright notice and this permission notice shall be included in all
16 | // copies or substantial portions of the Software.
17 | //
18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 | // SOFTWARE.
25 |
26 | import Foundation
27 |
28 | /// An array that is always sorted by an index
29 | /// This dramatically improves the performance of arrays that need to be sorted frequently
30 | open class IndexedArray {
31 |
32 | // --------------------
33 | // MARK: - Properties -
34 | // --------------------
35 |
36 | /// The backed array
37 | open fileprivate(set) var array = [T]()
38 |
39 | /// A closure that extracts the index from an array element
40 | fileprivate let _extractIndex: (T) -> U
41 |
42 |
43 |
44 | // --------------
45 | // MARK: - Init -
46 | // --------------
47 |
48 | /// Init the IndexedArray using the index extraction closure
49 | public init(extractIndex: @escaping (T) -> U) {
50 | _extractIndex = extractIndex
51 | }
52 |
53 |
54 |
55 | // -----------------
56 | // MARK: - Methods -
57 | // -----------------
58 |
59 | /// Add an element to the array
60 | /// The element will automatically be inserted in the right place
61 | open func add(_ element: T) {
62 | // Find the correct index
63 | let index = findIndex(element)
64 |
65 | if index == array.count {
66 | // Append the element if the array is not long enough
67 | array.append(element)
68 | } else {
69 | // Finally, insert the element in the right index
70 | array.insert(element, at: index)
71 | }
72 | }
73 |
74 | /// Force-sort if the index values were changed
75 | open func sort() {
76 | _ = array.sorted { self._extractIndex($0) < self._extractIndex($1) }
77 | }
78 |
79 | /// Removes the element at index from the array
80 | open func removeAtIndex(_ index: Int) {
81 | array.remove(at: index)
82 | }
83 |
84 | /// Finds the correct index in the array for an element
85 | fileprivate func findIndex(_ element: T) -> Int {
86 | // The index that the array is ordered by
87 | let index = _extractIndex(element)
88 | // The index we're currently using
89 | var currentSlice = halveIndex(array.count)
90 | var arrayIndex = currentSlice
91 | // Return 0 if there are no elements
92 | if array.count == 0 { return 0 }
93 |
94 | var iterations = 0
95 | while arrayIndex >= 0 && arrayIndex <= array.count {
96 | iterations += 1
97 | // Is this the correct index?
98 | var correctIndex = true
99 | var forward = true
100 |
101 | // Check if the element is correctly positioned
102 | if arrayIndex < array.count {
103 | let currentIndex = _extractIndex(array[arrayIndex])
104 | if currentIndex < index { correctIndex = false }
105 | }
106 | if arrayIndex-1 >= 0 {
107 | let previousIndex = _extractIndex(array[arrayIndex-1])
108 | if previousIndex > index {
109 | correctIndex = false
110 | forward = false
111 | }
112 | }
113 |
114 | // Return the index if it's correct
115 | if correctIndex { return arrayIndex }
116 | // Halve the slice again
117 | currentSlice = halveIndex(currentSlice)
118 | // Depending on the size of the index we either lower or raise the index
119 | arrayIndex += forward ? currentSlice : -currentSlice
120 | }
121 |
122 | // There was nothing found, we just return 0
123 | return 0
124 | }
125 |
126 | /// Halves the index (floor(x / 2.0))
127 | /// The index can't be 0 though
128 | fileprivate func halveIndex(_ index: Int) -> Int {
129 | let index = Int(floor(Double(index) / 2.0))
130 | return index > 0 ? index : 1
131 | }
132 |
133 | }
134 |
--------------------------------------------------------------------------------
/Pathfinder/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | FMWK
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | $(CURRENT_PROJECT_VERSION)
23 | NSPrincipalClass
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/Pathfinder/Map.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Map.swift
3 | // Pathfinder
4 | //
5 | // Created by Ilija Tovilo on 15/08/14.
6 | // Copyright (c) 2014 Ilija Tovilo
7 | //
8 | // Permission is hereby granted, free of charge, to any person obtaining a copy
9 | // of this software and associated documentation files (the "Software"), to deal
10 | // in the Software without restriction, including without limitation the rights
11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | // copies of the Software, and to permit persons to whom the Software is
13 | // furnished to do so, subject to the following conditions:
14 | //
15 | // The above copyright notice and this permission notice shall be included in all
16 | // copies or substantial portions of the Software.
17 | //
18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 | // SOFTWARE.
25 |
26 | import Foundation
27 |
28 | /// Map is an abstract class that can be overridden to created any type of map
29 | /// TODO: I ran into issues when making the Map a protocol. I'll try to do this in the future.
30 | open class Map {
31 |
32 | // --------------------
33 | // MARK: - Properties -
34 | // --------------------
35 |
36 | /// The function used to calculate the heuristic value
37 | var heuristicFunction: HeuristicFunction = .manhattan
38 |
39 |
40 |
41 | // -----------------
42 | // MARK: - Methods -
43 | // -----------------
44 |
45 | /// Returns the valid moves that can be performed from one node to the other
46 | func validMoves(_ node: Node) -> [Node] {
47 | assert(false, "Unimplemented")
48 | return []
49 | }
50 |
51 | /// Calculates the hValue from a node to the end node
52 | func hValueForNode(_ node: Node, endNode: Node) -> Int {
53 | assert(false, "Unimplemented")
54 | return 0
55 | }
56 |
57 | /// Calculates the move cost from one node to one of it's neighbour nodes
58 | func moveCostForNode(_ node: Node, toNode: Node) -> Int {
59 | assert(false, "Unimplemented")
60 | return 0
61 | }
62 |
63 | }
64 |
--------------------------------------------------------------------------------
/Pathfinder/Matrix.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Matrix.swift
3 | // Pathfinder
4 | //
5 | // Created by Ilija Tovilo on 30/07/14.
6 | // Copyright (c) 2014 Ilija Tovilo
7 | //
8 | // Permission is hereby granted, free of charge, to any person obtaining a copy
9 | // of this software and associated documentation files (the "Software"), to deal
10 | // in the Software without restriction, including without limitation the rights
11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | // copies of the Software, and to permit persons to whom the Software is
13 | // furnished to do so, subject to the following conditions:
14 | //
15 | // The above copyright notice and this permission notice shall be included in all
16 | // copies or substantial portions of the Software.
17 | //
18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 | // SOFTWARE.
25 |
26 | import Foundation
27 |
28 | /// A matrix is able to store values in 2 dimensional form
29 | // TODO: Make Objective-C compatible
30 | open class Matrix {
31 |
32 | // --------------------
33 | // MARK: - Properties -
34 | // --------------------
35 |
36 | /// The width of the matrix
37 | public let width: Int
38 |
39 | /// The height of the matrix
40 | public let height: Int
41 |
42 | /// Backed array that stores the elements of the matrix
43 | fileprivate var _elements: [T]
44 |
45 |
46 |
47 | // --------------
48 | // MARK: - Init -
49 | // --------------
50 |
51 | /// Init the matrix with a width, height, and a repeated value
52 | /// The repeated value is used, because a matrix can never have empty indexes
53 | /// If you specifically need empty indexes, just use Optionals
54 | public init(width: Int, height: Int, repeatedValue: (_ x: Int, _ y: Int) -> T) {
55 | // Sanity check
56 | assert(width >= 0, "The width of the matrix needs to be larger or equal to 0.")
57 | assert(height >= 0, "The height of the matrix needs to be larger or equal to 0.")
58 |
59 | // Init the variables
60 | self.width = width
61 | self.height = height
62 | _elements = Array(repeating: repeatedValue(0, 0), count: width*height)
63 |
64 | // Fill the matrix with the repeated value
65 | for x in 0.. T {
80 | get {
81 | // Sanity check
82 | assert(x >= 0 && x < self.width, "x needs to be larger or equal to zero and smaller than the width of the matrix.")
83 | assert(y >= 0 && y < self.height, "y needs to be larger or equal to zero and smaller than the height of the matrix.")
84 |
85 | return _elements[x + (y * width)]
86 | }
87 | set(newValue) {
88 | // Sanity check
89 | assert(x >= 0 && x < self.width, "x needs to be larger or equal to zero and smaller than the width of the matrix.")
90 | assert(y >= 0 && y < self.height, "y needs to be larger or equal to zero and smaller than the height of the matrix.")
91 |
92 | _elements[x + (y * width)] = newValue
93 | }
94 | }
95 |
96 | }
97 |
98 |
99 |
100 | // ----------------------
101 | // MARK: - SequenceType -
102 | // ----------------------
103 |
104 | extension Matrix: Sequence {
105 | /// Returns a generator to loop through the matrix
106 | public func makeIterator() -> MatrixGenerator {
107 | return MatrixGenerator(matrix: self)
108 | }
109 | }
110 |
111 | /// Generator used to enumerate through the matrix
112 | open class MatrixGenerator: IteratorProtocol {
113 | /// The backed matrix
114 | fileprivate let _matrix: Matrix
115 | /// The current x value
116 | fileprivate var _x = 0
117 | /// The current y value
118 | fileprivate var _y = 0
119 |
120 | /// Init the matrix generator using the matrix
121 | init(matrix: Matrix) {
122 | _matrix = matrix
123 | }
124 |
125 | /// Step through the matrix
126 | open func next() -> (x: Int, y: Int, element: T)? {
127 | // Sanity check
128 | if _x >= _matrix.width { return nil }
129 | if _y >= _matrix.height { return nil }
130 |
131 | // Extract the element and increase the counters
132 | let returnValue = (_x, _y, _matrix[_x, _y])
133 |
134 | // Increase the counters
135 | _x += 1
136 | if _x >= _matrix.width {
137 | _x = 0
138 | _y += 1
139 | }
140 |
141 | return returnValue
142 | }
143 |
144 | }
145 |
--------------------------------------------------------------------------------
/Pathfinder/Node.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Node.swift
3 | // Pathfinder
4 | //
5 | // Created by Ilija Tovilo on 15/08/14.
6 | // Copyright (c) 2014 Ilija Tovilo
7 | //
8 | // Permission is hereby granted, free of charge, to any person obtaining a copy
9 | // of this software and associated documentation files (the "Software"), to deal
10 | // in the Software without restriction, including without limitation the rights
11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | // copies of the Software, and to permit persons to whom the Software is
13 | // furnished to do so, subject to the following conditions:
14 | //
15 | // The above copyright notice and this permission notice shall be included in all
16 | // copies or substantial portions of the Software.
17 | //
18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 | // SOFTWARE.
25 |
26 | import Foundation
27 |
28 | /// Defines a unit on a map
29 | open class Node {
30 |
31 | // --------------
32 | // MARK: - Init -
33 | // --------------
34 |
35 | /// Init the node using it's coordinate
36 | /// The coordinate never changes
37 | public init(coordinates: Coordinates) {
38 | self.coordinates = coordinates
39 | }
40 |
41 |
42 | // --------------------
43 | // MARK: - Properties -
44 | // --------------------
45 |
46 | /// The coordinates of the node in the map
47 | public let coordinates: Coordinates
48 |
49 | /// Indicates if the node has been opened
50 | @objc
51 | open var opened: Bool = false
52 |
53 | /// Indicates if the node has been closed
54 | @objc
55 | open var closed: Bool = false
56 |
57 | /// Indicates if the node is accessible
58 | @objc
59 | open var accessible: Bool = true
60 |
61 | /// Heuristic Value
62 | @objc
63 | open var hValue: Int = 0
64 |
65 | /// Move Cost (+ move cost of parent)
66 | @objc
67 | open var gValue: Int = 0
68 |
69 | /// The total cost (h + g)
70 | @objc
71 | open var fValue: Int {
72 | return hValue + gValue
73 | }
74 |
75 | /// The parent node is used to lead back to the start node
76 | open var parent: Node?
77 |
78 |
79 |
80 | // -----------------
81 | // MARK: - Methods -
82 | // -----------------
83 |
84 | /// Reset the nodes properties
85 | @objc
86 | open func reset() {
87 | opened = false
88 | closed = false
89 | hValue = 0
90 | gValue = 0
91 | parent = nil
92 | }
93 |
94 | }
95 |
96 |
97 |
98 | // ------------------
99 | // MARK: - Hashable -
100 | // ------------------
101 |
102 | extension Node: Hashable {
103 | @objc
104 | public var hashValue: Int {
105 | return coordinates.hashValue
106 | }
107 | }
108 |
109 |
110 |
111 | // -------------------
112 | // MARK: - Printable -
113 | // -------------------
114 |
115 | extension Node: CustomStringConvertible {
116 | @objc
117 | public var description: String {
118 | return ""
119 | }
120 |
121 | }
122 |
123 |
124 | // -------------------
125 | // MARK: - Equatable -
126 | // -------------------
127 |
128 | extension Node: Equatable {}
129 | public func ==(l: Node, r: Node) -> Bool {
130 | return l === r
131 | }
132 |
--------------------------------------------------------------------------------
/Pathfinder/Pathfinder.h:
--------------------------------------------------------------------------------
1 | //
2 | // Pathfinder.h
3 | // Pathfinder
4 | //
5 | // Created by Ilija Tovilo on 15/08/14.
6 | // Copyright (c) 2014 Ilija Tovilo
7 | //
8 | // Permission is hereby granted, free of charge, to any person obtaining a copy
9 | // of this software and associated documentation files (the "Software"), to deal
10 | // in the Software without restriction, including without limitation the rights
11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | // copies of the Software, and to permit persons to whom the Software is
13 | // furnished to do so, subject to the following conditions:
14 | //
15 | // The above copyright notice and this permission notice shall be included in all
16 | // copies or substantial portions of the Software.
17 | //
18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 | // SOFTWARE.
25 |
26 |
27 | #import
28 |
29 | //! Project version number for Pathfinder.
30 | FOUNDATION_EXPORT double PathfinderVersionNumber;
31 |
32 | //! Project version string for Pathfinder.
33 | FOUNDATION_EXPORT const unsigned char PathfinderVersionString[];
34 |
35 | // In this header, you should import all the public headers of your framework using statements like #import
36 |
37 |
38 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | Pathfinder
2 | ==========
3 |
4 | Pathfinder is a pathfinding library for iOS and OS X written in Swift.
5 |
6 | 
7 | 
8 |
9 | ## Not maintained anymore
10 | GameplayKit now has [it's own pathfinder component](https://developer.apple.com/library/content/documentation/General/Conceptual/GameplayKit_Guide/Pathfinding.html). You should probably use that one instead.
11 |
12 | ## Usage
13 | Soon.
14 |
15 | ## Future
16 | - 3D Map support
17 | - More algorithms
18 |
19 | ## Things to note
20 | - Best performance is achieved when using the Release Build Configuration
21 | - I have not tested this on an iPhone
22 | - The demo is a mess, I'll clean that up soon
23 |
24 | ## License
25 | Pathfinder is available under the MIT license. See the LICENSE file for more info.
26 |
--------------------------------------------------------------------------------
/demo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iluuu1994/Pathfinder/07f2940a4a300313256acb22cd69e0a2747eac42/demo.png
--------------------------------------------------------------------------------
/demo2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iluuu1994/Pathfinder/07f2940a4a300313256acb22cd69e0a2747eac42/demo2.png
--------------------------------------------------------------------------------