From 47df42c8e585631611c9ef36e4fe961febf07c36 Mon Sep 17 00:00:00 2001 From: Eryn Wells Date: Sat, 10 Nov 2018 17:40:37 -0500 Subject: [PATCH] Add a basic Queue data structure Implemented as a linked list. --- Terrain.xcodeproj/project.pbxproj | 8 +++++ Terrain2/Algorithms.swift | 8 ++--- Terrain2/Queue.swift | 54 +++++++++++++++++++++++++++++++ Terrain2Tests/QueueTests.swift | 51 +++++++++++++++++++++++++++++ 4 files changed, 117 insertions(+), 4 deletions(-) create mode 100644 Terrain2/Queue.swift create mode 100644 Terrain2Tests/QueueTests.swift diff --git a/Terrain.xcodeproj/project.pbxproj b/Terrain.xcodeproj/project.pbxproj index db7da06..5493543 100644 --- a/Terrain.xcodeproj/project.pbxproj +++ b/Terrain.xcodeproj/project.pbxproj @@ -9,6 +9,8 @@ /* Begin PBXBuildFile section */ C018AD33219518080094BE3C /* Terrain2Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C018AD32219518080094BE3C /* Terrain2Tests.swift */; }; C018AD3B219518480094BE3C /* AlgorithmsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C018AD3A219518480094BE3C /* AlgorithmsTests.swift */; }; + C018AD4021978E690094BE3C /* Queue.swift in Sources */ = {isa = PBXBuildFile; fileRef = C018AD3F21978E690094BE3C /* Queue.swift */; }; + C018AD422197907B0094BE3C /* QueueTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C018AD412197907B0094BE3C /* QueueTests.swift */; }; C019C8512191CE7100EAD5BB /* Uniforms.m in Sources */ = {isa = PBXBuildFile; fileRef = C019C8502191CE7100EAD5BB /* Uniforms.m */; }; C08C58A0218F46F000EAFC2D /* Algorithms.swift in Sources */ = {isa = PBXBuildFile; fileRef = C08C589F218F46F000EAFC2D /* Algorithms.swift */; }; C08C58A2218F474E00EAFC2D /* TerrainAlgorithms.metal in Sources */ = {isa = PBXBuildFile; fileRef = C08C58A1218F474E00EAFC2D /* TerrainAlgorithms.metal */; }; @@ -46,6 +48,8 @@ C018AD32219518080094BE3C /* Terrain2Tests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Terrain2Tests.swift; sourceTree = ""; }; C018AD34219518080094BE3C /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; C018AD3A219518480094BE3C /* AlgorithmsTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AlgorithmsTests.swift; sourceTree = ""; }; + C018AD3F21978E690094BE3C /* Queue.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Queue.swift; sourceTree = ""; }; + C018AD412197907B0094BE3C /* QueueTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QueueTests.swift; sourceTree = ""; }; C019C8502191CE7100EAD5BB /* Uniforms.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = Uniforms.m; sourceTree = ""; }; C08C589F218F46F000EAFC2D /* Algorithms.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Algorithms.swift; sourceTree = ""; }; C08C58A1218F474E00EAFC2D /* TerrainAlgorithms.metal */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.metal; path = TerrainAlgorithms.metal; sourceTree = ""; }; @@ -107,6 +111,7 @@ children = ( C018AD32219518080094BE3C /* Terrain2Tests.swift */, C018AD3A219518480094BE3C /* AlgorithmsTests.swift */, + C018AD412197907B0094BE3C /* QueueTests.swift */, C018AD34219518080094BE3C /* Info.plist */, ); path = Terrain2Tests; @@ -176,6 +181,7 @@ C0C15AB6218E2A90007494E2 /* Renderer.swift */, C0C15AC5218E32B2007494E2 /* Terrain.swift */, C08C589F218F46F000EAFC2D /* Algorithms.swift */, + C018AD3F21978E690094BE3C /* Queue.swift */, C018AD3E219728890094BE3C /* Shaders */, C0C15ABA218E2A90007494E2 /* ShaderTypes.h */, C019C8502191CE7100EAD5BB /* Uniforms.m */, @@ -318,6 +324,7 @@ buildActionMask = 2147483647; files = ( C018AD33219518080094BE3C /* Terrain2Tests.swift in Sources */, + C018AD422197907B0094BE3C /* QueueTests.swift in Sources */, C018AD3B219518480094BE3C /* AlgorithmsTests.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -346,6 +353,7 @@ C0C15AB7218E2A90007494E2 /* Renderer.swift in Sources */, C0C15AB3218E2A90007494E2 /* AppDelegate.swift in Sources */, C019C8512191CE7100EAD5BB /* Uniforms.m in Sources */, + C018AD4021978E690094BE3C /* Queue.swift in Sources */, C08C58A0218F46F000EAFC2D /* Algorithms.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; diff --git a/Terrain2/Algorithms.swift b/Terrain2/Algorithms.swift index 410ef8e..0ea3736 100644 --- a/Terrain2/Algorithms.swift +++ b/Terrain2/Algorithms.swift @@ -222,11 +222,11 @@ public class DiamondSquareGenerator: TerrainGenerator { } func breadthFirstSearch(visit: (Box) -> (Void)) { - var queue = [self] - while queue.count > 0 { - let box = queue.removeFirst() + var queue = Queue() + queue.enqueue(item: self) + while let box = queue.dequeue() { visit(box) - queue.append(contentsOf: box.subdivisions) + queue.enqueue(items: box.subdivisions) } } } diff --git a/Terrain2/Queue.swift b/Terrain2/Queue.swift new file mode 100644 index 0000000..21bedb8 --- /dev/null +++ b/Terrain2/Queue.swift @@ -0,0 +1,54 @@ +// +// Queue.swift +// Terrain2 +// +// Created by Eryn Wells on 11/10/18. +// Copyright © 2018 Eryn Wells. All rights reserved. +// + +import Foundation + +struct Queue { + class Node { + var item: Element + var next: Node? + + init(item i: Element) { + item = i + } + } + + var count: Int = 0 + var head: Node? + var tail: Node? + + mutating func enqueue(item: Element) { + let newNode = Node(item: item) + if head == nil { + head = newNode + tail = newNode + } else { + tail!.next = newNode + tail = newNode + } + count += 1 + } + + mutating func enqueue(items: S) where Element == S.Element, S : Sequence { + for i in items { + enqueue(item: i) + } + } + + mutating func dequeue() -> Element? { + guard let oldHead = head else { + return nil + } + head = oldHead.next + if head == nil { + tail = nil + } + count -= 1 + return oldHead.item + } +} diff --git a/Terrain2Tests/QueueTests.swift b/Terrain2Tests/QueueTests.swift new file mode 100644 index 0000000..55f111b --- /dev/null +++ b/Terrain2Tests/QueueTests.swift @@ -0,0 +1,51 @@ +// +// QueueTests.swift +// Terrain2Tests +// +// Created by Eryn Wells on 11/10/18. +// Copyright © 2018 Eryn Wells. All rights reserved. +// + +import XCTest +@testable import Terrain2 + +class QueueTests: XCTestCase { + + func testEnqueue() { + var queue = Queue() + queue.enqueue(item: 1) + queue.enqueue(item: 2) + queue.enqueue(item: 3) + XCTAssertEqual(queue.count, 3) + XCTAssertEqual(queue.head?.item, 1) + XCTAssertEqual(queue.head?.next?.item, 2) + XCTAssertEqual(queue.head?.next?.next?.item, 3) + } + + func testDequeue() { + var queue = Queue() + queue.enqueue(item: 1) + queue.enqueue(item: 2) + queue.enqueue(item: 3) + + XCTAssertEqual(queue.count, 3) + XCTAssertEqual(queue.head?.item, 1) + XCTAssertEqual(queue.tail?.item, 3) + + XCTAssertEqual(queue.dequeue(), 1) + XCTAssertEqual(queue.count, 2) + XCTAssertEqual(queue.head?.item, 2) + XCTAssertEqual(queue.tail?.item, 3) + + XCTAssertEqual(queue.dequeue(), 2) + XCTAssertEqual(queue.count, 1) + XCTAssertEqual(queue.head?.item, 3) + XCTAssertEqual(queue.tail?.item, 3) + + XCTAssertEqual(queue.dequeue(), 3) + XCTAssertEqual(queue.count, 0) + XCTAssertNil(queue.head) + XCTAssertNil(queue.tail) + } + +}