├── Preview.gif
├── .gitignore
├── Preview
├── Sources
│ ├── AppDelegate.swift
│ └── PreviewWindowController.swift
└── Support
│ ├── Preview.entitlements
│ ├── Images.xcassets
│ └── AppIcon.appiconset
│ │ └── Contents.json
│ ├── Info.plist
│ └── Base.lproj
│ └── Main.storyboard
├── LangtonsAnt.xcodeproj
├── project.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcshareddata
│ │ └── IDEWorkspaceChecks.plist
└── project.pbxproj
├── LangtonsAnt
├── Sources
│ ├── Point.swift
│ ├── Size.swift
│ ├── PreferencesWindowController.swift
│ ├── Speed.swift
│ ├── Direction.swift
│ ├── Ant.swift
│ ├── Theme.swift
│ ├── Board.swift
│ ├── BoardView.swift
│ ├── Preferences.swift
│ └── LangtonsAntView.swift
└── Support
│ ├── LangtonsAnt.entitlements
│ ├── Info.plist
│ └── Preferences.xib
├── README.md
└── LICENSE
/Preview.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/soffes/langtons-ant/HEAD/Preview.gif
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | *.xcodeproj/xcuserdata
3 | *.xcodeproj/project.xcworkspace/xcuserdata
4 |
--------------------------------------------------------------------------------
/Preview/Sources/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | import AppKit
2 |
3 | @NSApplicationMain
4 | final class AppDelegate: NSObject, NSApplicationDelegate {}
5 |
--------------------------------------------------------------------------------
/LangtonsAnt.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/LangtonsAnt/Sources/Point.swift:
--------------------------------------------------------------------------------
1 | public struct Point: Hashable {
2 |
3 | // MARK: - Properties
4 |
5 | public let x: Int
6 | public let y: Int
7 |
8 | // MARK: - Initializers
9 |
10 | public init(x: Int, y: Int) {
11 | self.x = x
12 | self.y = y
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/Preview/Support/Preview.entitlements:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | com.apple.security.app-sandbox
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/LangtonsAnt/Support/LangtonsAnt.entitlements:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | com.apple.security.app-sandbox
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/LangtonsAnt/Sources/Size.swift:
--------------------------------------------------------------------------------
1 | public struct Size: Equatable {
2 |
3 | // MARK: - Properties
4 |
5 | public let width: Int
6 | public let height: Int
7 |
8 | // MARK: - Initializers
9 |
10 | public init(width: Int, height: Int) {
11 | self.width = width
12 | self.height = height
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/LangtonsAnt.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/LangtonsAnt/Sources/PreferencesWindowController.swift:
--------------------------------------------------------------------------------
1 | import AppKit
2 |
3 | final class PreferencesWindowController: NSWindowController {
4 | override var windowNibName: String? {
5 | return "Preferences"
6 | }
7 |
8 | @IBAction func close(_ sender: Any?) {
9 | guard let window = window else { return }
10 | window.sheetParent?.endSheet(window)
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/LangtonsAnt/Sources/Speed.swift:
--------------------------------------------------------------------------------
1 | enum Speed: Int {
2 | case slow = 1
3 | case normal
4 | case fast
5 | case insane
6 |
7 | var framesPerSecond: UInt {
8 | switch self {
9 | case .slow:
10 | return 2
11 | case .normal:
12 | return 15
13 | case .fast:
14 | return 30
15 | case .insane:
16 | return 60
17 | }
18 | }
19 |
20 | var ticksPerFrame: UInt {
21 | switch self {
22 | case .slow:
23 | return 1
24 | case .normal:
25 | return 1
26 | case .fast:
27 | return 1
28 | case .insane:
29 | return 10
30 | }
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/LangtonsAnt/Sources/Direction.swift:
--------------------------------------------------------------------------------
1 | public enum Direction {
2 |
3 | // MARK: - Cases
4 |
5 | case north
6 | case east
7 | case south
8 | case west
9 |
10 | // MARK: - Properties
11 |
12 | public var turningRight: Direction {
13 | switch self {
14 | case .north: return .east
15 | case .east: return .south
16 | case .south: return .west
17 | case .west: return .north
18 | }
19 | }
20 |
21 | public var turningLeft: Direction {
22 | switch self {
23 | case .north: return .west
24 | case .east: return .north
25 | case .south: return .east
26 | case .west: return .south
27 | }
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/LangtonsAnt/Sources/Ant.swift:
--------------------------------------------------------------------------------
1 | public struct Ant {
2 |
3 | // MARK: - Properties
4 |
5 | public let name: String
6 | public var position: Point
7 | public var heading: Direction
8 |
9 | // MARK: - Turning
10 |
11 | public mutating func turnLeft() {
12 | heading = heading.turningLeft
13 | }
14 |
15 | public mutating func turnRight() {
16 | heading = heading.turningRight
17 | }
18 |
19 | // MARK: - Moving
20 |
21 | public mutating func moveForward() {
22 | switch heading {
23 | case .north:
24 | position = Point(x: position.x, y: position.y - 1)
25 | case .east:
26 | position = Point(x: position.x + 1, y: position.y)
27 | case .south:
28 | position = Point(x: position.x, y: position.y + 1)
29 | case .west:
30 | position = Point(x: position.x - 1, y: position.y)
31 | }
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/LangtonsAnt/Sources/Theme.swift:
--------------------------------------------------------------------------------
1 | import AppKit
2 |
3 | protocol Theme {
4 | var backgroundColor: NSColor { get }
5 | var filledColor: NSColor { get }
6 | var noiseColor: NSColor { get }
7 | var antColors: [NSColor] { get }
8 | }
9 |
10 | extension Theme {
11 | var antColors: [NSColor] {
12 | return [.red, .green, .blue, .cyan, .yellow, .magenta, .orange, .purple, .brown]
13 | }
14 | }
15 |
16 | struct LightTheme: Theme {
17 | var backgroundColor: NSColor {
18 | .white
19 | }
20 |
21 | var filledColor: NSColor {
22 | .black
23 | }
24 |
25 | var noiseColor: NSColor {
26 | NSColor(white: 0.8, alpha: 1)
27 | }
28 | }
29 |
30 | struct DarkTheme: Theme {
31 | var backgroundColor: NSColor {
32 | .black
33 | }
34 |
35 | var filledColor: NSColor {
36 | .white
37 | }
38 |
39 | var noiseColor: NSColor {
40 | NSColor(white: 0.2, alpha: 1)
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Langton’s Ant
2 |
3 | Swift macOS screen saver implementation of [Langton’s Ant](https://en.wikipedia.org/wiki/Langton%27s_ant).
4 |
5 | > Langton’s Ant is a two-dimensional universal Turing machine with a very simple set of rules but complex emergent behavior. It was invented by Chris Langton in 1986.
6 |
7 | It’s fascinating because it only uses the following two rules to generate everything you see:
8 |
9 | * At an unfilled square, turn 90° right, flip the color of the square, move forward one unit
10 | * At a filled square, turn 90° left, flip the color of the square, move forward one unit
11 |
12 | 
13 |
14 |
15 | ## Installation
16 |
17 | **[Download the latest release](https://github.com/soffes/langtons-ant/releases).** Unzip and double-click.
18 |
19 |
20 | ## Preferences
21 |
22 | Don’t forget to check out “Screen Saver Options…” in System Preferences. You can change the model and style to your liking.
23 |
--------------------------------------------------------------------------------
/LangtonsAnt/Support/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 | BNDL
17 | CFBundleShortVersionString
18 | 0.1
19 | CFBundleVersion
20 | 0
21 | NSHumanReadableCopyright
22 | Copyright © 2017 Sam Soffes. All rights reserved.
23 | NSPrincipalClass
24 | $(PRODUCT_MODULE_NAME).LangtonsAntView
25 |
26 |
27 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2017-2024 Sam Soffes, https://soff.es
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining
4 | a copy of this software and associated documentation files (the
5 | "Software"), to deal in the Software without restriction, including
6 | without limitation the rights to use, copy, modify, merge, publish,
7 | distribute, sublicense, and/or sell copies of the Software, and to
8 | permit persons to whom the Software is furnished to do so, subject to
9 | the following conditions:
10 |
11 | The above copyright notice and this permission notice shall be
12 | included in all copies or substantial portions of the Software.
13 |
14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 |
--------------------------------------------------------------------------------
/Preview/Support/Images.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "mac",
5 | "size" : "16x16",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "mac",
10 | "size" : "16x16",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "mac",
15 | "size" : "32x32",
16 | "scale" : "1x"
17 | },
18 | {
19 | "idiom" : "mac",
20 | "size" : "32x32",
21 | "scale" : "2x"
22 | },
23 | {
24 | "idiom" : "mac",
25 | "size" : "128x128",
26 | "scale" : "1x"
27 | },
28 | {
29 | "idiom" : "mac",
30 | "size" : "128x128",
31 | "scale" : "2x"
32 | },
33 | {
34 | "idiom" : "mac",
35 | "size" : "256x256",
36 | "scale" : "1x"
37 | },
38 | {
39 | "idiom" : "mac",
40 | "size" : "256x256",
41 | "scale" : "2x"
42 | },
43 | {
44 | "idiom" : "mac",
45 | "size" : "512x512",
46 | "scale" : "1x"
47 | },
48 | {
49 | "idiom" : "mac",
50 | "size" : "512x512",
51 | "scale" : "2x"
52 | }
53 | ],
54 | "info" : {
55 | "version" : 1,
56 | "author" : "xcode"
57 | }
58 | }
--------------------------------------------------------------------------------
/Preview/Sources/PreviewWindowController.swift:
--------------------------------------------------------------------------------
1 | import AppKit
2 |
3 | final class PreviewWindowController: NSWindowController {
4 |
5 | // MARK: - Properties
6 |
7 | private let screenSaverView = LangtonsAntView()
8 | private var timer: Timer? {
9 | willSet {
10 | timer?.invalidate()
11 | }
12 | }
13 |
14 | // MARK: - NSWindowController
15 |
16 | override func windowDidLoad() {
17 | super.windowDidLoad()
18 |
19 | window?.contentView = screenSaverView
20 |
21 | NotificationCenter.default.addObserver(self, selector: #selector(updateTimer),
22 | name: Preferences.speedDidChange, object: nil)
23 |
24 | updateTimer()
25 | }
26 |
27 | // MARK: - Actions
28 |
29 | @IBAction func showPreferences(_ sender: NSObject?) {
30 | guard let sheet = screenSaverView.configureSheet, let window else {
31 | return
32 | }
33 |
34 | window.beginSheet(sheet) { _ in
35 | sheet.close()
36 | }
37 | }
38 |
39 | // MARK: - Private
40 |
41 | @objc
42 | private func updateTimer() {
43 | timer = Timer.scheduledTimer(timeInterval: screenSaverView.animationTimeInterval, target: screenSaverView,
44 | selector: #selector(LangtonsAntView.animateOneFrame), userInfo: nil, repeats: true)
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/Preview/Support/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIconFile
10 |
11 | CFBundleIdentifier
12 | $(PRODUCT_BUNDLE_IDENTIFIER)
13 | CFBundleInfoDictionaryVersion
14 | 6.0
15 | CFBundleName
16 | $(PRODUCT_NAME)
17 | CFBundlePackageType
18 | APPL
19 | CFBundleShortVersionString
20 | 1.0
21 | CFBundleSignature
22 | ????
23 | CFBundleVersion
24 | 1
25 | LSApplicationCategoryType
26 | public.app-category.utilities
27 | LSMinimumSystemVersion
28 | $(MACOSX_DEPLOYMENT_TARGET)
29 | NSHumanReadableCopyright
30 | Copyright © 2015 Sam Soffes. All rights reserved.
31 | NSMainStoryboardFile
32 | Main
33 | NSPrincipalClass
34 | NSApplication
35 |
36 |
37 |
--------------------------------------------------------------------------------
/LangtonsAnt/Sources/Board.swift:
--------------------------------------------------------------------------------
1 | public struct Board {
2 |
3 | // MARK: - Properties
4 |
5 | public let size: Size
6 | public private(set) var ants = [Ant]()
7 | public private(set) var filled = Set()
8 | public var noise = Set()
9 |
10 | // MARK: - Initializers
11 |
12 | public init(size: Size) {
13 | self.size = size
14 | }
15 |
16 | // MARK: - Subscript
17 |
18 | public subscript(_ point: Point) -> Bool {
19 | get {
20 | return filled.contains(point) || noise.contains(point)
21 | }
22 |
23 | set(newValue) {
24 | if newValue {
25 | filled.insert(point)
26 | } else {
27 | filled.remove(point)
28 | }
29 |
30 | noise.remove(point)
31 | }
32 | }
33 |
34 | // MARK: - Adding & Removing Ants
35 |
36 | public mutating func addAnt(named name: String, at point: Point, heading: Direction = .south) {
37 | add(Ant(name: name, position: point, heading: heading))
38 | }
39 |
40 | public mutating func add(_ ant: Ant) {
41 | ants.append(ant)
42 | }
43 |
44 | public mutating func removeAnt(named name: String) {
45 | if let index = ants.firstIndex(where: { $0.name == name }) {
46 | ants.remove(at: index)
47 | }
48 | }
49 |
50 | // MARK: - Advancing Time
51 |
52 | public mutating func tick() {
53 | for (i, ant) in ants.enumerated() {
54 | var updated = ant
55 | let isFilled = self[ant.position]
56 |
57 | // At a filled square, turn 90° left
58 | if isFilled {
59 | updated.turnLeft()
60 | }
61 |
62 | // At a unfilled square, turn 90° right
63 | else {
64 | updated.turnRight()
65 | }
66 |
67 | // Flip the color of the square
68 | self[ant.position] = !isFilled
69 |
70 | // Move forward one unit
71 | updated.moveForward()
72 |
73 | ants[i] = updated
74 | }
75 | }
76 | }
77 |
--------------------------------------------------------------------------------
/LangtonsAnt/Sources/BoardView.swift:
--------------------------------------------------------------------------------
1 | import AppKit
2 |
3 | final class BoardView: NSView {
4 |
5 | // MARK: - Properties
6 |
7 | var board: Board {
8 | didSet {
9 | if oldValue.size != board.size {
10 | invalidateIntrinsicContentSize()
11 | }
12 |
13 | setNeedsDisplay(bounds)
14 | }
15 | }
16 |
17 | private let scale: CGFloat
18 |
19 | var theme: Theme {
20 | didSet {
21 | setNeedsDisplay(bounds)
22 | }
23 | }
24 |
25 | // MARK: - Initializers
26 |
27 | init(board: Board, scale: CGFloat, theme: Theme = LightTheme()) {
28 | self.board = board
29 | self.scale = scale
30 | self.theme = theme
31 | super.init(frame: .zero)
32 | }
33 |
34 | @available(*, unavailable)
35 | required init?(coder aDecoder: NSCoder) {
36 | fatalError("\(#function) has not been implemented")
37 | }
38 |
39 | // MARK: - UIView
40 |
41 | override var intrinsicContentSize: CGSize {
42 | CGSize(width: CGFloat(board.size.width) * scale, height: CGFloat(board.size.height) * scale)
43 | }
44 |
45 | override func draw(_ rect: CGRect) {
46 | guard let context = NSGraphicsContext.current?.cgContext else {
47 | return
48 | }
49 |
50 | // Background
51 | context.setFillColor(theme.backgroundColor.cgColor)
52 | context.fill(bounds)
53 |
54 | // Noise
55 | context.setFillColor(theme.noiseColor.cgColor)
56 | for point in board.noise {
57 | let rect = CGRect(x: scale * CGFloat(point.x), y: scale * CGFloat(point.y), width: scale, height: scale)
58 | context.fill(rect)
59 | }
60 |
61 | // Points
62 | context.setFillColor(theme.filledColor.cgColor)
63 | for point in board.filled {
64 | let rect = CGRect(x: scale * CGFloat(point.x), y: scale * CGFloat(point.y), width: scale, height: scale)
65 | context.fill(rect)
66 | }
67 |
68 | // Ants
69 | for (i, ant) in board.ants.enumerated() {
70 | context.setFillColor(theme.antColors[i].cgColor)
71 | context.fill(CGRect(x: scale * CGFloat(ant.position.x), y: scale * CGFloat(ant.position.y), width: scale, height: scale))
72 | }
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/LangtonsAnt/Sources/Preferences.swift:
--------------------------------------------------------------------------------
1 | import ScreenSaver
2 |
3 | final class Preferences: NSObject {
4 |
5 | // MARK: - Types
6 |
7 | static let boardDidChange = Notification.Name(rawValue: "Preferences.boardDidChange")
8 | static let speedDidChange = Notification.Name(rawValue: "Preferences.speedDidChange")
9 | static let themeDidChange = Notification.Name(rawValue: "Preferences.themeDidChange")
10 |
11 | private enum Key: String {
12 | case speed
13 | case numberOfAnts
14 | case darkMode
15 | case noiseAmount
16 |
17 | var notificationName: Notification.Name {
18 | switch self {
19 | case .speed:
20 | return Preferences.speedDidChange
21 | case .darkMode:
22 | return Preferences.themeDidChange
23 | default:
24 | return Preferences.boardDidChange
25 | }
26 | }
27 | }
28 |
29 | // MARK: - Properties
30 |
31 | var speed: Speed {
32 | get {
33 | return Speed(rawValue: speedInteger) ?? .normal
34 | }
35 |
36 | set {
37 | speedInteger = newValue.rawValue
38 | }
39 | }
40 |
41 | @objc
42 | var speedInteger: Int {
43 | get {
44 | let speed = Speed(rawValue: Self.defaults.integer(forKey: Key.speed.rawValue)) ?? .normal
45 | return speed.rawValue
46 | }
47 |
48 | set {
49 | let key = Key.speed
50 | let speed = Speed(rawValue: newValue) ?? .normal
51 |
52 | Self.defaults.set(speed.rawValue, forKey: key.rawValue)
53 | Self.defaults.synchronize()
54 |
55 | NotificationCenter.default.post(name: key.notificationName, object: nil)
56 | }
57 | }
58 |
59 | @objc
60 | var noiseAmount: Int {
61 | get {
62 | Self.defaults.integer(forKey: Key.noiseAmount.rawValue)
63 | }
64 |
65 | set {
66 | let key = Key.noiseAmount
67 | let value = min(35, max(0, newValue))
68 |
69 | Self.defaults.set(value, forKey: key.rawValue)
70 | Self.defaults.synchronize()
71 |
72 | NotificationCenter.default.post(name: key.notificationName, object: nil)
73 | }
74 | }
75 |
76 | @objc
77 | var numberOfAnts: Int {
78 | get {
79 | Self.defaults.integer(forKey: Key.numberOfAnts.rawValue)
80 | }
81 |
82 | set {
83 | let key = Key.numberOfAnts
84 |
85 | Self.defaults.set(min(9, max(1, newValue)), forKey: key.rawValue)
86 | Self.defaults.synchronize()
87 |
88 | NotificationCenter.default.post(name: key.notificationName, object: nil)
89 | }
90 | }
91 |
92 | @objc
93 | var darkMode: Bool {
94 | get {
95 | Self.defaults.bool(forKey: Key.darkMode.rawValue)
96 | }
97 |
98 | set {
99 | let key = Key.darkMode
100 |
101 | Self.defaults.set(newValue, forKey: key.rawValue)
102 | Self.defaults.synchronize()
103 |
104 | NotificationCenter.default.post(name: key.notificationName, object: nil)
105 | }
106 | }
107 |
108 | private static let defaults: UserDefaults = {
109 | let bundleIdentifier = Bundle(for: Preferences.self).bundleIdentifier!
110 | let defaults = ScreenSaverDefaults(forModuleWithName: bundleIdentifier) ?? UserDefaults.standard
111 | defaults.register(defaults: [
112 | Key.speed.rawValue: Speed.normal.rawValue,
113 | Key.numberOfAnts.rawValue: 4,
114 | Key.noiseAmount.rawValue: 10,
115 | Key.darkMode.rawValue: true
116 | ])
117 | return defaults
118 | }()
119 | }
120 |
--------------------------------------------------------------------------------
/LangtonsAnt/Sources/LangtonsAntView.swift:
--------------------------------------------------------------------------------
1 | import ScreenSaver
2 |
3 | @objc
4 | public final class LangtonsAntView: ScreenSaverView {
5 |
6 | // MARK: - Properties
7 |
8 | private var speed: Speed = .normal
9 |
10 | private var boardView: BoardView? {
11 | willSet {
12 | boardView?.removeFromSuperview()
13 | }
14 | }
15 |
16 | private var previousSize: CGSize = .zero
17 |
18 | private let preferences = Preferences()
19 |
20 | private var preferencesWindowController: PreferencesWindowController? {
21 | willSet {
22 | preferencesWindowController?.close()
23 | }
24 | }
25 |
26 | // MARK: - Initializers
27 |
28 | public override init?(frame: NSRect, isPreview: Bool) {
29 | super.init(frame: frame, isPreview: isPreview)
30 | initialize()
31 | }
32 |
33 | public required init?(coder: NSCoder) {
34 | super.init(coder: coder)
35 | initialize()
36 | }
37 |
38 |
39 | // MARK: - NSView
40 |
41 | public override func viewDidMoveToWindow() {
42 | super.viewDidMoveToWindow()
43 | setupBoard()
44 | }
45 |
46 | public override func resizeSubviews(withOldSize oldSize: NSSize) {
47 | super.resizeSubviews(withOldSize: oldSize)
48 | setupBoard()
49 | }
50 |
51 | public override func draw(_ rect: NSRect) {
52 | guard let context = NSGraphicsContext.current?.cgContext else { return }
53 |
54 | context.setFillColor(boardView?.theme.backgroundColor.cgColor ?? NSColor.black.cgColor)
55 | context.fill(bounds)
56 | }
57 |
58 | // MARK: - ScreenSaverView
59 |
60 | public override func animateOneFrame() {
61 | for _ in 0.. 0 {
104 | var noise = Set()
105 | for x in 0..
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 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
--------------------------------------------------------------------------------
/LangtonsAnt.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 54;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | 210668F02C12B36600D070B6 /* Ant.swift in Sources */ = {isa = PBXBuildFile; fileRef = 210668DF2C12B36600D070B6 /* Ant.swift */; };
11 | 210668F12C12B36600D070B6 /* Board.swift in Sources */ = {isa = PBXBuildFile; fileRef = 210668E02C12B36600D070B6 /* Board.swift */; };
12 | 210668F22C12B36600D070B6 /* BoardView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 210668E12C12B36600D070B6 /* BoardView.swift */; };
13 | 210668F32C12B36600D070B6 /* Direction.swift in Sources */ = {isa = PBXBuildFile; fileRef = 210668E22C12B36600D070B6 /* Direction.swift */; };
14 | 210668F42C12B36600D070B6 /* LangtonsAntView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 210668E32C12B36600D070B6 /* LangtonsAntView.swift */; };
15 | 210668F52C12B36600D070B6 /* Point.swift in Sources */ = {isa = PBXBuildFile; fileRef = 210668E42C12B36600D070B6 /* Point.swift */; };
16 | 210668F62C12B36600D070B6 /* Preferences.swift in Sources */ = {isa = PBXBuildFile; fileRef = 210668E52C12B36600D070B6 /* Preferences.swift */; };
17 | 210668F72C12B36600D070B6 /* PreferencesWindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 210668E62C12B36600D070B6 /* PreferencesWindowController.swift */; };
18 | 210668F82C12B36600D070B6 /* Size.swift in Sources */ = {isa = PBXBuildFile; fileRef = 210668E72C12B36600D070B6 /* Size.swift */; };
19 | 210668F92C12B36600D070B6 /* Speed.swift in Sources */ = {isa = PBXBuildFile; fileRef = 210668E82C12B36600D070B6 /* Speed.swift */; };
20 | 210668FA2C12B36600D070B6 /* Theme.swift in Sources */ = {isa = PBXBuildFile; fileRef = 210668E92C12B36600D070B6 /* Theme.swift */; };
21 | 210668FC2C12B36600D070B6 /* Preferences.xib in Resources */ = {isa = PBXBuildFile; fileRef = 210668ED2C12B36600D070B6 /* Preferences.xib */; };
22 | 210668FD2C12B36D00D070B6 /* PreferencesWindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 210668E62C12B36600D070B6 /* PreferencesWindowController.swift */; };
23 | 210668FE2C12B36D00D070B6 /* Speed.swift in Sources */ = {isa = PBXBuildFile; fileRef = 210668E82C12B36600D070B6 /* Speed.swift */; };
24 | 210668FF2C12B36D00D070B6 /* Board.swift in Sources */ = {isa = PBXBuildFile; fileRef = 210668E02C12B36600D070B6 /* Board.swift */; };
25 | 210669002C12B36D00D070B6 /* Theme.swift in Sources */ = {isa = PBXBuildFile; fileRef = 210668E92C12B36600D070B6 /* Theme.swift */; };
26 | 210669012C12B36D00D070B6 /* LangtonsAntView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 210668E32C12B36600D070B6 /* LangtonsAntView.swift */; };
27 | 210669022C12B36D00D070B6 /* BoardView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 210668E12C12B36600D070B6 /* BoardView.swift */; };
28 | 210669032C12B36D00D070B6 /* Ant.swift in Sources */ = {isa = PBXBuildFile; fileRef = 210668DF2C12B36600D070B6 /* Ant.swift */; };
29 | 210669042C12B36D00D070B6 /* Point.swift in Sources */ = {isa = PBXBuildFile; fileRef = 210668E42C12B36600D070B6 /* Point.swift */; };
30 | 210669052C12B36D00D070B6 /* Size.swift in Sources */ = {isa = PBXBuildFile; fileRef = 210668E72C12B36600D070B6 /* Size.swift */; };
31 | 210669062C12B36D00D070B6 /* Preferences.swift in Sources */ = {isa = PBXBuildFile; fileRef = 210668E52C12B36600D070B6 /* Preferences.swift */; };
32 | 210669072C12B36D00D070B6 /* Direction.swift in Sources */ = {isa = PBXBuildFile; fileRef = 210668E22C12B36600D070B6 /* Direction.swift */; };
33 | 210669082C12B37B00D070B6 /* Preferences.xib in Resources */ = {isa = PBXBuildFile; fileRef = 210668ED2C12B36600D070B6 /* Preferences.xib */; };
34 | 218920EC1F50F1BD00B03FCE /* PreviewWindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 218920E41F50F1BD00B03FCE /* PreviewWindowController.swift */; };
35 | 218920ED1F50F1BD00B03FCE /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 218920E51F50F1BD00B03FCE /* AppDelegate.swift */; };
36 | 218920EE1F50F1BD00B03FCE /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 218920E81F50F1BD00B03FCE /* Main.storyboard */; };
37 | 218920EF1F50F1BD00B03FCE /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 218920EA1F50F1BD00B03FCE /* Images.xcassets */; };
38 | /* End PBXBuildFile section */
39 |
40 | /* Begin PBXFileReference section */
41 | 210668DF2C12B36600D070B6 /* Ant.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Ant.swift; sourceTree = ""; };
42 | 210668E02C12B36600D070B6 /* Board.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Board.swift; sourceTree = ""; };
43 | 210668E12C12B36600D070B6 /* BoardView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BoardView.swift; sourceTree = ""; };
44 | 210668E22C12B36600D070B6 /* Direction.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Direction.swift; sourceTree = ""; };
45 | 210668E32C12B36600D070B6 /* LangtonsAntView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LangtonsAntView.swift; sourceTree = ""; };
46 | 210668E42C12B36600D070B6 /* Point.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Point.swift; sourceTree = ""; };
47 | 210668E52C12B36600D070B6 /* Preferences.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Preferences.swift; sourceTree = ""; };
48 | 210668E62C12B36600D070B6 /* PreferencesWindowController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PreferencesWindowController.swift; sourceTree = ""; };
49 | 210668E72C12B36600D070B6 /* Size.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Size.swift; sourceTree = ""; };
50 | 210668E82C12B36600D070B6 /* Speed.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Speed.swift; sourceTree = ""; };
51 | 210668E92C12B36600D070B6 /* Theme.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Theme.swift; sourceTree = ""; };
52 | 210668EB2C12B36600D070B6 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
53 | 210668EC2C12B36600D070B6 /* LangtonsAnt.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = LangtonsAnt.entitlements; sourceTree = ""; };
54 | 210668ED2C12B36600D070B6 /* Preferences.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = Preferences.xib; sourceTree = ""; };
55 | 211873911F50D8F1005F7DE7 /* LangtonsAnt.saver */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = LangtonsAnt.saver; sourceTree = BUILT_PRODUCTS_DIR; };
56 | 211873A21F50D8FE005F7DE7 /* Preview.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Preview.app; sourceTree = BUILT_PRODUCTS_DIR; };
57 | 218920E41F50F1BD00B03FCE /* PreviewWindowController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PreviewWindowController.swift; sourceTree = ""; };
58 | 218920E51F50F1BD00B03FCE /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; };
59 | 218920E71F50F1BD00B03FCE /* Preview.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = Preview.entitlements; sourceTree = ""; };
60 | 218920E91F50F1BD00B03FCE /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; };
61 | 218920EA1F50F1BD00B03FCE /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; };
62 | 218920EB1F50F1BD00B03FCE /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
63 | /* End PBXFileReference section */
64 |
65 | /* Begin PBXFrameworksBuildPhase section */
66 | 2118738D1F50D8F1005F7DE7 /* Frameworks */ = {
67 | isa = PBXFrameworksBuildPhase;
68 | buildActionMask = 2147483647;
69 | files = (
70 | );
71 | runOnlyForDeploymentPostprocessing = 0;
72 | };
73 | 2118739F1F50D8FE005F7DE7 /* Frameworks */ = {
74 | isa = PBXFrameworksBuildPhase;
75 | buildActionMask = 2147483647;
76 | files = (
77 | );
78 | runOnlyForDeploymentPostprocessing = 0;
79 | };
80 | /* End PBXFrameworksBuildPhase section */
81 |
82 | /* Begin PBXGroup section */
83 | 210668EA2C12B36600D070B6 /* Sources */ = {
84 | isa = PBXGroup;
85 | children = (
86 | 210668DF2C12B36600D070B6 /* Ant.swift */,
87 | 210668E02C12B36600D070B6 /* Board.swift */,
88 | 210668E12C12B36600D070B6 /* BoardView.swift */,
89 | 210668E22C12B36600D070B6 /* Direction.swift */,
90 | 210668E32C12B36600D070B6 /* LangtonsAntView.swift */,
91 | 210668E42C12B36600D070B6 /* Point.swift */,
92 | 210668E52C12B36600D070B6 /* Preferences.swift */,
93 | 210668E62C12B36600D070B6 /* PreferencesWindowController.swift */,
94 | 210668E72C12B36600D070B6 /* Size.swift */,
95 | 210668E82C12B36600D070B6 /* Speed.swift */,
96 | 210668E92C12B36600D070B6 /* Theme.swift */,
97 | );
98 | path = Sources;
99 | sourceTree = "";
100 | };
101 | 210668EE2C12B36600D070B6 /* Support */ = {
102 | isa = PBXGroup;
103 | children = (
104 | 210668EB2C12B36600D070B6 /* Info.plist */,
105 | 210668EC2C12B36600D070B6 /* LangtonsAnt.entitlements */,
106 | 210668ED2C12B36600D070B6 /* Preferences.xib */,
107 | );
108 | path = Support;
109 | sourceTree = "";
110 | };
111 | 210668EF2C12B36600D070B6 /* LangtonsAnt */ = {
112 | isa = PBXGroup;
113 | children = (
114 | 210668EA2C12B36600D070B6 /* Sources */,
115 | 210668EE2C12B36600D070B6 /* Support */,
116 | );
117 | path = LangtonsAnt;
118 | sourceTree = "";
119 | };
120 | 211873871F50D8F1005F7DE7 = {
121 | isa = PBXGroup;
122 | children = (
123 | 210668EF2C12B36600D070B6 /* LangtonsAnt */,
124 | 211873A31F50D8FE005F7DE7 /* Preview */,
125 | 211873921F50D8F1005F7DE7 /* Products */,
126 | );
127 | sourceTree = "";
128 | usesTabs = 1;
129 | };
130 | 211873921F50D8F1005F7DE7 /* Products */ = {
131 | isa = PBXGroup;
132 | children = (
133 | 211873911F50D8F1005F7DE7 /* LangtonsAnt.saver */,
134 | 211873A21F50D8FE005F7DE7 /* Preview.app */,
135 | );
136 | name = Products;
137 | sourceTree = "";
138 | };
139 | 211873A31F50D8FE005F7DE7 /* Preview */ = {
140 | isa = PBXGroup;
141 | children = (
142 | 218920E31F50F1BD00B03FCE /* Sources */,
143 | 218920E61F50F1BD00B03FCE /* Support */,
144 | );
145 | path = Preview;
146 | sourceTree = "";
147 | };
148 | 218920E31F50F1BD00B03FCE /* Sources */ = {
149 | isa = PBXGroup;
150 | children = (
151 | 218920E51F50F1BD00B03FCE /* AppDelegate.swift */,
152 | 218920E41F50F1BD00B03FCE /* PreviewWindowController.swift */,
153 | );
154 | path = Sources;
155 | sourceTree = "";
156 | };
157 | 218920E61F50F1BD00B03FCE /* Support */ = {
158 | isa = PBXGroup;
159 | children = (
160 | 218920E81F50F1BD00B03FCE /* Main.storyboard */,
161 | 218920EA1F50F1BD00B03FCE /* Images.xcassets */,
162 | 218920E71F50F1BD00B03FCE /* Preview.entitlements */,
163 | 218920EB1F50F1BD00B03FCE /* Info.plist */,
164 | );
165 | path = Support;
166 | sourceTree = "";
167 | };
168 | /* End PBXGroup section */
169 |
170 | /* Begin PBXHeadersBuildPhase section */
171 | 2118738E1F50D8F1005F7DE7 /* Headers */ = {
172 | isa = PBXHeadersBuildPhase;
173 | buildActionMask = 2147483647;
174 | files = (
175 | );
176 | runOnlyForDeploymentPostprocessing = 0;
177 | };
178 | /* End PBXHeadersBuildPhase section */
179 |
180 | /* Begin PBXNativeTarget section */
181 | 211873901F50D8F1005F7DE7 /* LangtonsAnt */ = {
182 | isa = PBXNativeTarget;
183 | buildConfigurationList = 2118739B1F50D8F1005F7DE7 /* Build configuration list for PBXNativeTarget "LangtonsAnt" */;
184 | buildPhases = (
185 | 2118738C1F50D8F1005F7DE7 /* Sources */,
186 | 2118738D1F50D8F1005F7DE7 /* Frameworks */,
187 | 2118738E1F50D8F1005F7DE7 /* Headers */,
188 | 2118738F1F50D8F1005F7DE7 /* Resources */,
189 | 218921071F519B6900B03FCE /* Set Version */,
190 | );
191 | buildRules = (
192 | );
193 | dependencies = (
194 | );
195 | name = LangtonsAnt;
196 | productName = "Langton’s Ant";
197 | productReference = 211873911F50D8F1005F7DE7 /* LangtonsAnt.saver */;
198 | productType = "com.apple.product-type.bundle";
199 | };
200 | 211873A11F50D8FE005F7DE7 /* Preview */ = {
201 | isa = PBXNativeTarget;
202 | buildConfigurationList = 211873AE1F50D8FE005F7DE7 /* Build configuration list for PBXNativeTarget "Preview" */;
203 | buildPhases = (
204 | 2118739E1F50D8FE005F7DE7 /* Sources */,
205 | 2118739F1F50D8FE005F7DE7 /* Frameworks */,
206 | 211873A01F50D8FE005F7DE7 /* Resources */,
207 | );
208 | buildRules = (
209 | );
210 | dependencies = (
211 | );
212 | name = Preview;
213 | productName = Preview;
214 | productReference = 211873A21F50D8FE005F7DE7 /* Preview.app */;
215 | productType = "com.apple.product-type.application";
216 | };
217 | /* End PBXNativeTarget section */
218 |
219 | /* Begin PBXProject section */
220 | 211873881F50D8F1005F7DE7 /* Project object */ = {
221 | isa = PBXProject;
222 | attributes = {
223 | BuildIndependentTargetsInParallel = YES;
224 | LastSwiftUpdateCheck = 0830;
225 | LastUpgradeCheck = 1530;
226 | ORGANIZATIONNAME = "Sam Soffes";
227 | TargetAttributes = {
228 | 211873901F50D8F1005F7DE7 = {
229 | CreatedOnToolsVersion = 8.3.3;
230 | LastSwiftMigration = 0830;
231 | ProvisioningStyle = Manual;
232 | };
233 | 211873A11F50D8FE005F7DE7 = {
234 | CreatedOnToolsVersion = 8.3.3;
235 | DevelopmentTeam = LHDXBG4XBK;
236 | ProvisioningStyle = Automatic;
237 | SystemCapabilities = {
238 | com.apple.Sandbox = {
239 | enabled = 1;
240 | };
241 | };
242 | };
243 | };
244 | };
245 | buildConfigurationList = 2118738B1F50D8F1005F7DE7 /* Build configuration list for PBXProject "LangtonsAnt" */;
246 | compatibilityVersion = "Xcode 3.2";
247 | developmentRegion = en;
248 | hasScannedForEncodings = 0;
249 | knownRegions = (
250 | en,
251 | Base,
252 | );
253 | mainGroup = 211873871F50D8F1005F7DE7;
254 | productRefGroup = 211873921F50D8F1005F7DE7 /* Products */;
255 | projectDirPath = "";
256 | projectRoot = "";
257 | targets = (
258 | 211873901F50D8F1005F7DE7 /* LangtonsAnt */,
259 | 211873A11F50D8FE005F7DE7 /* Preview */,
260 | );
261 | };
262 | /* End PBXProject section */
263 |
264 | /* Begin PBXResourcesBuildPhase section */
265 | 2118738F1F50D8F1005F7DE7 /* Resources */ = {
266 | isa = PBXResourcesBuildPhase;
267 | buildActionMask = 2147483647;
268 | files = (
269 | 210668FC2C12B36600D070B6 /* Preferences.xib in Resources */,
270 | );
271 | runOnlyForDeploymentPostprocessing = 0;
272 | };
273 | 211873A01F50D8FE005F7DE7 /* Resources */ = {
274 | isa = PBXResourcesBuildPhase;
275 | buildActionMask = 2147483647;
276 | files = (
277 | 218920EE1F50F1BD00B03FCE /* Main.storyboard in Resources */,
278 | 210669082C12B37B00D070B6 /* Preferences.xib in Resources */,
279 | 218920EF1F50F1BD00B03FCE /* Images.xcassets in Resources */,
280 | );
281 | runOnlyForDeploymentPostprocessing = 0;
282 | };
283 | /* End PBXResourcesBuildPhase section */
284 |
285 | /* Begin PBXShellScriptBuildPhase section */
286 | 218921071F519B6900B03FCE /* Set Version */ = {
287 | isa = PBXShellScriptBuildPhase;
288 | buildActionMask = 2147483647;
289 | files = (
290 | );
291 | inputPaths = (
292 | );
293 | name = "Set Version";
294 | outputPaths = (
295 | );
296 | runOnlyForDeploymentPostprocessing = 0;
297 | shellPath = "/usr/bin/env ruby";
298 | shellScript = "git = `sh /etc/profile; which git`.chomp\napp_build = `#{git} rev-list HEAD --count`.chomp.to_i\n`/usr/libexec/PlistBuddy -c \"Set :CFBundleVersion #{app_build}\" \"${TARGET_BUILD_DIR}/${INFOPLIST_PATH}\"`\nputs \"Updated #{ENV['TARGET_BUILD_DIR']}/#{ENV['INFOPLIST_PATH']}\"";
299 | };
300 | /* End PBXShellScriptBuildPhase section */
301 |
302 | /* Begin PBXSourcesBuildPhase section */
303 | 2118738C1F50D8F1005F7DE7 /* Sources */ = {
304 | isa = PBXSourcesBuildPhase;
305 | buildActionMask = 2147483647;
306 | files = (
307 | 210668F22C12B36600D070B6 /* BoardView.swift in Sources */,
308 | 210668F62C12B36600D070B6 /* Preferences.swift in Sources */,
309 | 210668F12C12B36600D070B6 /* Board.swift in Sources */,
310 | 210668F92C12B36600D070B6 /* Speed.swift in Sources */,
311 | 210668FA2C12B36600D070B6 /* Theme.swift in Sources */,
312 | 210668F52C12B36600D070B6 /* Point.swift in Sources */,
313 | 210668F82C12B36600D070B6 /* Size.swift in Sources */,
314 | 210668F02C12B36600D070B6 /* Ant.swift in Sources */,
315 | 210668F42C12B36600D070B6 /* LangtonsAntView.swift in Sources */,
316 | 210668F72C12B36600D070B6 /* PreferencesWindowController.swift in Sources */,
317 | 210668F32C12B36600D070B6 /* Direction.swift in Sources */,
318 | );
319 | runOnlyForDeploymentPostprocessing = 0;
320 | };
321 | 2118739E1F50D8FE005F7DE7 /* Sources */ = {
322 | isa = PBXSourcesBuildPhase;
323 | buildActionMask = 2147483647;
324 | files = (
325 | 210668FD2C12B36D00D070B6 /* PreferencesWindowController.swift in Sources */,
326 | 210668FE2C12B36D00D070B6 /* Speed.swift in Sources */,
327 | 210668FF2C12B36D00D070B6 /* Board.swift in Sources */,
328 | 210669002C12B36D00D070B6 /* Theme.swift in Sources */,
329 | 210669012C12B36D00D070B6 /* LangtonsAntView.swift in Sources */,
330 | 210669022C12B36D00D070B6 /* BoardView.swift in Sources */,
331 | 210669032C12B36D00D070B6 /* Ant.swift in Sources */,
332 | 210669042C12B36D00D070B6 /* Point.swift in Sources */,
333 | 210669052C12B36D00D070B6 /* Size.swift in Sources */,
334 | 210669062C12B36D00D070B6 /* Preferences.swift in Sources */,
335 | 210669072C12B36D00D070B6 /* Direction.swift in Sources */,
336 | 218920ED1F50F1BD00B03FCE /* AppDelegate.swift in Sources */,
337 | 218920EC1F50F1BD00B03FCE /* PreviewWindowController.swift in Sources */,
338 | );
339 | runOnlyForDeploymentPostprocessing = 0;
340 | };
341 | /* End PBXSourcesBuildPhase section */
342 |
343 | /* Begin PBXVariantGroup section */
344 | 218920E81F50F1BD00B03FCE /* Main.storyboard */ = {
345 | isa = PBXVariantGroup;
346 | children = (
347 | 218920E91F50F1BD00B03FCE /* Base */,
348 | );
349 | name = Main.storyboard;
350 | sourceTree = "";
351 | };
352 | /* End PBXVariantGroup section */
353 |
354 | /* Begin XCBuildConfiguration section */
355 | 211873991F50D8F1005F7DE7 /* Debug */ = {
356 | isa = XCBuildConfiguration;
357 | buildSettings = {
358 | ALWAYS_SEARCH_USER_PATHS = NO;
359 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
360 | CLANG_ANALYZER_NONNULL = YES;
361 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
362 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
363 | CLANG_CXX_LIBRARY = "libc++";
364 | CLANG_ENABLE_MODULES = YES;
365 | CLANG_ENABLE_OBJC_ARC = YES;
366 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
367 | CLANG_WARN_BOOL_CONVERSION = YES;
368 | CLANG_WARN_COMMA = YES;
369 | CLANG_WARN_CONSTANT_CONVERSION = YES;
370 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
371 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
372 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
373 | CLANG_WARN_EMPTY_BODY = YES;
374 | CLANG_WARN_ENUM_CONVERSION = YES;
375 | CLANG_WARN_INFINITE_RECURSION = YES;
376 | CLANG_WARN_INT_CONVERSION = YES;
377 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
378 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
379 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
380 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
381 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
382 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
383 | CLANG_WARN_STRICT_PROTOTYPES = YES;
384 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
385 | CLANG_WARN_UNREACHABLE_CODE = YES;
386 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
387 | CODE_SIGN_IDENTITY = "-";
388 | COPY_PHASE_STRIP = NO;
389 | DEAD_CODE_STRIPPING = YES;
390 | DEBUG_INFORMATION_FORMAT = dwarf;
391 | ENABLE_STRICT_OBJC_MSGSEND = YES;
392 | ENABLE_TESTABILITY = YES;
393 | ENABLE_USER_SCRIPT_SANDBOXING = YES;
394 | GCC_C_LANGUAGE_STANDARD = gnu99;
395 | GCC_DYNAMIC_NO_PIC = NO;
396 | GCC_NO_COMMON_BLOCKS = YES;
397 | GCC_OPTIMIZATION_LEVEL = 0;
398 | GCC_PREPROCESSOR_DEFINITIONS = (
399 | "DEBUG=1",
400 | "$(inherited)",
401 | );
402 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
403 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
404 | GCC_WARN_UNDECLARED_SELECTOR = YES;
405 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
406 | GCC_WARN_UNUSED_FUNCTION = YES;
407 | GCC_WARN_UNUSED_VARIABLE = YES;
408 | MACOSX_DEPLOYMENT_TARGET = 10.13;
409 | MTL_ENABLE_DEBUG_INFO = YES;
410 | ONLY_ACTIVE_ARCH = YES;
411 | SDKROOT = macosx;
412 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
413 | SWIFT_VERSION = 5.0;
414 | };
415 | name = Debug;
416 | };
417 | 2118739A1F50D8F1005F7DE7 /* Release */ = {
418 | isa = XCBuildConfiguration;
419 | buildSettings = {
420 | ALWAYS_SEARCH_USER_PATHS = NO;
421 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
422 | CLANG_ANALYZER_NONNULL = YES;
423 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
424 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
425 | CLANG_CXX_LIBRARY = "libc++";
426 | CLANG_ENABLE_MODULES = YES;
427 | CLANG_ENABLE_OBJC_ARC = YES;
428 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
429 | CLANG_WARN_BOOL_CONVERSION = YES;
430 | CLANG_WARN_COMMA = YES;
431 | CLANG_WARN_CONSTANT_CONVERSION = YES;
432 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
433 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
434 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
435 | CLANG_WARN_EMPTY_BODY = YES;
436 | CLANG_WARN_ENUM_CONVERSION = YES;
437 | CLANG_WARN_INFINITE_RECURSION = YES;
438 | CLANG_WARN_INT_CONVERSION = YES;
439 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
440 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
441 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
442 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
443 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
444 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
445 | CLANG_WARN_STRICT_PROTOTYPES = YES;
446 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
447 | CLANG_WARN_UNREACHABLE_CODE = YES;
448 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
449 | CODE_SIGN_IDENTITY = "-";
450 | COPY_PHASE_STRIP = NO;
451 | DEAD_CODE_STRIPPING = YES;
452 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
453 | ENABLE_NS_ASSERTIONS = NO;
454 | ENABLE_STRICT_OBJC_MSGSEND = YES;
455 | ENABLE_USER_SCRIPT_SANDBOXING = YES;
456 | GCC_C_LANGUAGE_STANDARD = gnu99;
457 | GCC_NO_COMMON_BLOCKS = YES;
458 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
459 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
460 | GCC_WARN_UNDECLARED_SELECTOR = YES;
461 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
462 | GCC_WARN_UNUSED_FUNCTION = YES;
463 | GCC_WARN_UNUSED_VARIABLE = YES;
464 | MACOSX_DEPLOYMENT_TARGET = 10.13;
465 | MTL_ENABLE_DEBUG_INFO = NO;
466 | SDKROOT = macosx;
467 | SWIFT_COMPILATION_MODE = wholemodule;
468 | SWIFT_OPTIMIZATION_LEVEL = "-O";
469 | SWIFT_VERSION = 5.0;
470 | };
471 | name = Release;
472 | };
473 | 2118739C1F50D8F1005F7DE7 /* Debug */ = {
474 | isa = XCBuildConfiguration;
475 | buildSettings = {
476 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
477 | CLANG_ENABLE_MODULES = YES;
478 | CODE_SIGN_ENTITLEMENTS = LangtonsAnt/Support/LangtonsAnt.entitlements;
479 | CODE_SIGN_IDENTITY = "Apple Development";
480 | COMBINE_HIDPI_IMAGES = YES;
481 | DEAD_CODE_STRIPPING = YES;
482 | DEVELOPMENT_TEAM = UP9C8XM22A;
483 | "DEVELOPMENT_TEAM[sdk=macosx*]" = LHDXBG4XBK;
484 | INFOPLIST_FILE = "$(SRCROOT)/LangtonsAnt/Support/Info.plist";
485 | INSTALL_PATH = "$(HOME)/Library/Screen Savers";
486 | LD_RUNPATH_SEARCH_PATHS = (
487 | "$(inherited)",
488 | "@executable_path/../Frameworks",
489 | "@loader_path/../Frameworks",
490 | );
491 | PRODUCT_BUNDLE_IDENTIFIER = "com.samsoffes.langtons-ant";
492 | PRODUCT_MODULE_NAME = LangtonsAnt;
493 | PRODUCT_NAME = "$(TARGET_NAME)";
494 | PROVISIONING_PROFILE_SPECIFIER = "";
495 | WRAPPER_EXTENSION = saver;
496 | };
497 | name = Debug;
498 | };
499 | 2118739D1F50D8F1005F7DE7 /* Release */ = {
500 | isa = XCBuildConfiguration;
501 | buildSettings = {
502 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
503 | CLANG_ENABLE_MODULES = YES;
504 | CODE_SIGN_ENTITLEMENTS = LangtonsAnt/Support/LangtonsAnt.entitlements;
505 | CODE_SIGN_IDENTITY = "Apple Development";
506 | COMBINE_HIDPI_IMAGES = YES;
507 | DEAD_CODE_STRIPPING = YES;
508 | DEVELOPMENT_TEAM = UP9C8XM22A;
509 | "DEVELOPMENT_TEAM[sdk=macosx*]" = LHDXBG4XBK;
510 | INFOPLIST_FILE = "$(SRCROOT)/LangtonsAnt/Support/Info.plist";
511 | INSTALL_PATH = "$(HOME)/Library/Screen Savers";
512 | LD_RUNPATH_SEARCH_PATHS = (
513 | "$(inherited)",
514 | "@executable_path/../Frameworks",
515 | "@loader_path/../Frameworks",
516 | );
517 | PRODUCT_BUNDLE_IDENTIFIER = "com.samsoffes.langtons-ant";
518 | PRODUCT_MODULE_NAME = LangtonsAnt;
519 | PRODUCT_NAME = "$(TARGET_NAME)";
520 | PROVISIONING_PROFILE_SPECIFIER = "";
521 | WRAPPER_EXTENSION = saver;
522 | };
523 | name = Release;
524 | };
525 | 211873AF1F50D8FE005F7DE7 /* Debug */ = {
526 | isa = XCBuildConfiguration;
527 | buildSettings = {
528 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
529 | CODE_SIGN_ENTITLEMENTS = Preview/Support/Preview.entitlements;
530 | "CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development";
531 | COMBINE_HIDPI_IMAGES = YES;
532 | DEAD_CODE_STRIPPING = YES;
533 | DEVELOPMENT_TEAM = LHDXBG4XBK;
534 | INFOPLIST_FILE = "$(SRCROOT)/Preview/Support/Info.plist";
535 | LD_RUNPATH_SEARCH_PATHS = (
536 | "$(inherited)",
537 | "@executable_path/../Frameworks",
538 | );
539 | MACOSX_DEPLOYMENT_TARGET = "$(RECOMMENDED_MACOSX_DEPLOYMENT_TARGET)";
540 | PRODUCT_BUNDLE_IDENTIFIER = "com.samsoffes.langtons-ant.preview";
541 | PRODUCT_NAME = "$(TARGET_NAME)";
542 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
543 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
544 | };
545 | name = Debug;
546 | };
547 | 211873B01F50D8FE005F7DE7 /* Release */ = {
548 | isa = XCBuildConfiguration;
549 | buildSettings = {
550 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
551 | CODE_SIGN_ENTITLEMENTS = Preview/Support/Preview.entitlements;
552 | "CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development";
553 | COMBINE_HIDPI_IMAGES = YES;
554 | DEAD_CODE_STRIPPING = YES;
555 | DEVELOPMENT_TEAM = LHDXBG4XBK;
556 | INFOPLIST_FILE = "$(SRCROOT)/Preview/Support/Info.plist";
557 | LD_RUNPATH_SEARCH_PATHS = (
558 | "$(inherited)",
559 | "@executable_path/../Frameworks",
560 | );
561 | MACOSX_DEPLOYMENT_TARGET = "$(RECOMMENDED_MACOSX_DEPLOYMENT_TARGET)";
562 | PRODUCT_BUNDLE_IDENTIFIER = "com.samsoffes.langtons-ant.preview";
563 | PRODUCT_NAME = "$(TARGET_NAME)";
564 | SWIFT_COMPILATION_MODE = wholemodule;
565 | SWIFT_OPTIMIZATION_LEVEL = "-O";
566 | };
567 | name = Release;
568 | };
569 | /* End XCBuildConfiguration section */
570 |
571 | /* Begin XCConfigurationList section */
572 | 2118738B1F50D8F1005F7DE7 /* Build configuration list for PBXProject "LangtonsAnt" */ = {
573 | isa = XCConfigurationList;
574 | buildConfigurations = (
575 | 211873991F50D8F1005F7DE7 /* Debug */,
576 | 2118739A1F50D8F1005F7DE7 /* Release */,
577 | );
578 | defaultConfigurationIsVisible = 0;
579 | defaultConfigurationName = Release;
580 | };
581 | 2118739B1F50D8F1005F7DE7 /* Build configuration list for PBXNativeTarget "LangtonsAnt" */ = {
582 | isa = XCConfigurationList;
583 | buildConfigurations = (
584 | 2118739C1F50D8F1005F7DE7 /* Debug */,
585 | 2118739D1F50D8F1005F7DE7 /* Release */,
586 | );
587 | defaultConfigurationIsVisible = 0;
588 | defaultConfigurationName = Release;
589 | };
590 | 211873AE1F50D8FE005F7DE7 /* Build configuration list for PBXNativeTarget "Preview" */ = {
591 | isa = XCConfigurationList;
592 | buildConfigurations = (
593 | 211873AF1F50D8FE005F7DE7 /* Debug */,
594 | 211873B01F50D8FE005F7DE7 /* Release */,
595 | );
596 | defaultConfigurationIsVisible = 0;
597 | defaultConfigurationName = Release;
598 | };
599 | /* End XCConfigurationList section */
600 | };
601 | rootObject = 211873881F50D8F1005F7DE7 /* Project object */;
602 | }
603 |
--------------------------------------------------------------------------------
/Preview/Support/Base.lproj/Main.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
645 |
646 |
647 |
648 |
649 |
650 |
651 |
652 |
653 |
654 |
655 |
656 |
657 |
658 |
659 |
660 |
661 |
662 |
663 |
664 |
665 |
666 |
667 |
668 |
669 |
670 |
671 |
--------------------------------------------------------------------------------