diff --git a/README.md b/README.md index 7c72ad1..ca7423f 100644 --- a/README.md +++ b/README.md @@ -5,8 +5,12 @@ A few preliminary notes: * This playground requires the new playground format and features released in Xcode 7 and Swift 2. This version requires Yosemite. * From time to time playgrounds can crash or seem to disappear from time to time. The current fix suggested by Apple is to show the package contents of the playground and delete the workspace. -* Type "turtle" in the playground. You should see "Turtle_Sources.Turtle" on the right. Mouse over it and you will see the quick look icon and the show value icon. Click on the show value icon. You should see a rectangle with a turtle in the middle. Enlarge the box if you like. -* Make the turtle move by typing in "forward()". Make the turtle turn by typing in "right()". +* Type "turtle" in the Linear Turtle playground page. You should see "Linear_Turtle_with_Target_PageSources.Turtle" on the right. Mouse over it and you will see the quick look icon and the show value icon. Click on the show value icon. You should see a rectangle with a turtle in the middle. Enlarge the box if you like. +* Make the turtle move by typing in "forward() or back()". Stop when you've hit your target'. +* In the next page add the functions right() and left(). +* In the next page the four functions can take arguments specifying how much to move forward() or back() and how much to turn right() or left(). +* In the next page you can change colors using penColor() or nextColor(). +* In the final page you can show() and hide() the icon or control the pen using penUp() or penDown(). * Create routines and your own functions. I am working on a book that will serve as a tutorial using this playground. It will be available soon. diff --git a/Turtle.playground/Pages/Before We Begin.xcplaygroundpage/Contents.swift b/Turtle.playground/Pages/Before We Begin.xcplaygroundpage/Contents.swift new file mode 100644 index 0000000..cc54c68 --- /dev/null +++ b/Turtle.playground/Pages/Before We Begin.xcplaygroundpage/Contents.swift @@ -0,0 +1,15 @@ +/*: +### Before We Begin +[TOC](Contents) | Previous | [Next](@next) + +--- +We need to save the position of our target or it will constantly be moving around. + +* Find your `Documents` director. +* Add a new folder named `Shared Playground Data` making sure that there's a space between each word. + +Enjoy! + +--- + +[TOC](TOC) | Previous | [Next](@next) */ diff --git a/Turtle.playground/Pages/Contents.xcplaygroundpage/Contents.swift b/Turtle.playground/Pages/Contents.xcplaygroundpage/Contents.swift new file mode 100644 index 0000000..e7b8faf --- /dev/null +++ b/Turtle.playground/Pages/Contents.xcplaygroundpage/Contents.swift @@ -0,0 +1,9 @@ +/*: +### The Turtle Playground +* [Before We Begin](Before%20We%20Begin) +* [Linear Turtle with Target](Linear%20Turtle%20with%20Target) +* [Turtle with Target](Turtle%20with%20Target) +* [Turtle with Parameters and Target](Turtle%20with%20Parameters%20and%20Target) +* [Cosmic Turtle and Target](Cosmic%20Turtle%20and%20Target) +* [Turtle](Turtle) +*/ diff --git a/Turtle.playground/Pages/Cosmic Turtle and Target Hint.xcplaygroundpage/Contents.swift b/Turtle.playground/Pages/Cosmic Turtle and Target Hint.xcplaygroundpage/Contents.swift new file mode 100644 index 0000000..ff0fcd2 --- /dev/null +++ b/Turtle.playground/Pages/Cosmic Turtle and Target Hint.xcplaygroundpage/Contents.swift @@ -0,0 +1,9 @@ +/*: +### Cosmic Turtle and Target Hints + +[Back](Cosmic%20Turtle%20and%20Target) + +--- +* The `penColor()` and `nextColor()` functions are used to set the pen's color or to cycle through them. +* The colors included are Red, Orange, Yellow, PeaGreen, Green, BlueGreen, Cyan, Cerullian, Blue, Purple, Magenta, Pink +*/ diff --git a/Turtle.playground/Pages/Cosmic Turtle and Target.xcplaygroundpage/Contents.swift b/Turtle.playground/Pages/Cosmic Turtle and Target.xcplaygroundpage/Contents.swift new file mode 100644 index 0000000..81a9f6c --- /dev/null +++ b/Turtle.playground/Pages/Cosmic Turtle and Target.xcplaygroundpage/Contents.swift @@ -0,0 +1,8 @@ +/*: +### Cosmic Turtle and Target ([Hint](Cosmic%20Turtle%20and%20Target%20Hint)) + +[TOC](Contents) | [Previous](@previous) | [Next](@next) + +--- +*/ + diff --git a/Turtle.playground/Pages/Cosmic Turtle and Target.xcplaygroundpage/Resources/RightArrow.png b/Turtle.playground/Pages/Cosmic Turtle and Target.xcplaygroundpage/Resources/RightArrow.png new file mode 100644 index 0000000..91688d8 Binary files /dev/null and b/Turtle.playground/Pages/Cosmic Turtle and Target.xcplaygroundpage/Resources/RightArrow.png differ diff --git a/Turtle.playground/Pages/Cosmic Turtle and Target.xcplaygroundpage/Resources/Target.png b/Turtle.playground/Pages/Cosmic Turtle and Target.xcplaygroundpage/Resources/Target.png new file mode 100644 index 0000000..cb3c7c2 Binary files /dev/null and b/Turtle.playground/Pages/Cosmic Turtle and Target.xcplaygroundpage/Resources/Target.png differ diff --git a/Turtle.playground/Pages/Cosmic Turtle and Target.xcplaygroundpage/Resources/Turtle.png b/Turtle.playground/Pages/Cosmic Turtle and Target.xcplaygroundpage/Resources/Turtle.png new file mode 100644 index 0000000..d78537f Binary files /dev/null and b/Turtle.playground/Pages/Cosmic Turtle and Target.xcplaygroundpage/Resources/Turtle.png differ diff --git a/Turtle.playground/Pages/Cosmic Turtle and Target.xcplaygroundpage/Sources/Secret Turtle Stuff/Avatar.swift b/Turtle.playground/Pages/Cosmic Turtle and Target.xcplaygroundpage/Sources/Secret Turtle Stuff/Avatar.swift new file mode 100644 index 0000000..6bd39c1 --- /dev/null +++ b/Turtle.playground/Pages/Cosmic Turtle and Target.xcplaygroundpage/Sources/Secret Turtle Stuff/Avatar.swift @@ -0,0 +1,57 @@ +import UIKit + +struct Avatar { + private(set) var view = UIImageView() + private(set) var headingInRadians = 0.0 + private let image: UIImage + + // MARK: - Initializers + + init(){ + image = UIImage(named: "Turtle.png")! + view = UIImageView(image: colorAvatar(initialPenColor)) + } + + private init(view: UIImageView, image: UIImage, headingInRadians: Double) { + self.view = view + self.headingInRadians = headingInRadians + self.image = image + } + + // MARK: - Direction + + func increaseHeadingBy(degrees: Double) -> Avatar { + return Avatar(view: view, image: image, headingInRadians: headingInRadians + degrees/180 * M_PI ) + } + + + // MARK: - Position + + func positionTransform(currentPoint: CGPoint) -> CGAffineTransform { + let rotateByRadians = CGAffineTransformMakeRotation(CGFloat(headingInRadians)) + let centerOfTurtleX = currentPoint.x - view.center.x + let centerOfTurtleY = currentPoint.y - view.center.y + let moveTurtle = CGAffineTransformMakeTranslation(centerOfTurtleX, centerOfTurtleY) + let turtleTransform = CGAffineTransformConcat(rotateByRadians, moveTurtle) + return turtleTransform + } + + // MARK: - Color + + func penColor(penColor: PenColor) -> Avatar { + view.image = colorAvatar(penColor) + return Avatar(view: view, image: image, headingInRadians: headingInRadians) + } + + private func colorAvatar(penColor: PenColor) -> UIImage { + let angle = penColor.hue * M_PI * 2.0 + guard let inputImage = CIImage(image: image), + let hueAdjuster = CIFilter(name: "CIHueAdjust", withInputParameters: [kCIInputImageKey : inputImage , + kCIInputAngleKey : NSNumber(double: angle)]) else { + return image + } + return UIImage(CIImage: hueAdjuster.outputImage!) + } + + +} \ No newline at end of file diff --git a/Turtle.playground/Pages/Cosmic Turtle and Target.xcplaygroundpage/Sources/Secret Turtle Stuff/Constants.swift b/Turtle.playground/Pages/Cosmic Turtle and Target.xcplaygroundpage/Sources/Secret Turtle Stuff/Constants.swift new file mode 100644 index 0000000..67758f8 --- /dev/null +++ b/Turtle.playground/Pages/Cosmic Turtle and Target.xcplaygroundpage/Sources/Secret Turtle Stuff/Constants.swift @@ -0,0 +1,24 @@ +import UIKit + +let centerX = 300 +let centerY = 300 +let width = 2 * centerX +let height = 2 * centerY +let terrarium = CGRect(x: 0, y: 0, width: width, height: height) + +let lineWidth: CGFloat = 4.0 + +private let targetOffset = 25 +let targetHorizontalOffset = targetOffset +let targetVerticalOffset = targetOffset +let targetSteps = 11 + +let targetWidth = 2 * targetHorizontalOffset +let targetHeight = 2 * targetVerticalOffset + +let standardForwardDistance = 2 * targetOffset +let rightAngle = 90 + +let environmentColor = UIColor.blackColor() +let initialPenColor = PenColor.Green +let victoryColor = UIColor.lightGrayColor() diff --git a/Turtle.playground/Pages/Cosmic Turtle and Target.xcplaygroundpage/Sources/Secret Turtle Stuff/Path.swift b/Turtle.playground/Pages/Cosmic Turtle and Target.xcplaygroundpage/Sources/Secret Turtle Stuff/Path.swift new file mode 100644 index 0000000..8f5dd38 --- /dev/null +++ b/Turtle.playground/Pages/Cosmic Turtle and Target.xcplaygroundpage/Sources/Secret Turtle Stuff/Path.swift @@ -0,0 +1,39 @@ +import UIKit + +struct Path { + var bezierPath = UIBezierPath() + var currentPoint: CGPoint { + return bezierPath.currentPoint + } + let penColor: PenColor + + // MARK: - Initializers + + init(startingPoint: CGPoint, penColor: PenColor = initialPenColor) { + bezierPath.moveToPoint(startingPoint) + bezierPath.lineWidth = lineWidth + self.penColor = penColor + } + + private init(bezierPath: UIBezierPath, penColor: PenColor) { + self.bezierPath = bezierPath + self.penColor = penColor + } + + // MARK: - Position + + func moveTo(x x:Double, y: Double) -> Path { + bezierPath.addLineToPoint(CGPoint(x: x, y: y)) + return Path(bezierPath: bezierPath, penColor: penColor) + } + + func forward(distance: Double, inDirection headingInRadians: Double) -> Path { + let dx = distance * cos(headingInRadians) + let dy = distance * sin(headingInRadians) + let currentX = Double(bezierPath.currentPoint.x) + let currentY = Double(bezierPath.currentPoint.y) + return moveTo(x: currentX + dx, y: currentY + dy) + } + +} + diff --git a/Turtle.playground/Pages/Cosmic Turtle and Target.xcplaygroundpage/Sources/Secret Turtle Stuff/PenColor.swift b/Turtle.playground/Pages/Cosmic Turtle and Target.xcplaygroundpage/Sources/Secret Turtle Stuff/PenColor.swift new file mode 100644 index 0000000..22daeb2 --- /dev/null +++ b/Turtle.playground/Pages/Cosmic Turtle and Target.xcplaygroundpage/Sources/Secret Turtle Stuff/PenColor.swift @@ -0,0 +1,25 @@ +import UIKit + +public enum PenColor: Int { + case Red + case Orange + case Yellow + case PeaGreen, Green, BlueGreen + case Cyan, Cerullian, Blue + case Purple, Magenta, Pink + + + var color: UIColor { + return UIColor(hue: CGFloat(hue), saturation: 1, brightness: 1, alpha: 1) + } + + func next() -> PenColor { + let numberOfNextColor = (rawValue + 7) % PenColor.Pink.rawValue + return PenColor(rawValue: numberOfNextColor)! + } + + var hue: Double { + return Double(rawValue)/12.0 + } +} + diff --git a/Turtle.playground/Pages/Cosmic Turtle and Target.xcplaygroundpage/Sources/Secret Turtle Stuff/TargetView.swift b/Turtle.playground/Pages/Cosmic Turtle and Target.xcplaygroundpage/Sources/Secret Turtle Stuff/TargetView.swift new file mode 100644 index 0000000..717903c --- /dev/null +++ b/Turtle.playground/Pages/Cosmic Turtle and Target.xcplaygroundpage/Sources/Secret Turtle Stuff/TargetView.swift @@ -0,0 +1,61 @@ +import UIKit +import XCPlayground +import GameKit + +struct Target { + static private let path = (XCPSharedDataDirectoryPath as NSString).stringByAppendingPathComponent("Target.plist") + let targetView = UIImageView(image: UIImage(named: "Target.png")) + let startingMarkerView = UIImageView(image: UIImage(named: "RightArrow.png")) + let targetCoordinateX: Int + let targetCoordinateY: Int + + init() { + (targetCoordinateX, targetCoordinateY) = Target.readFromFile() + positionTargetAndStartingView() + } + private init(targetCoordinateX: Int, targetCoordinateY: Int) { + self.targetCoordinateX = targetCoordinateX + self.targetCoordinateY = targetCoordinateY + positionTargetAndStartingView() + } + + func positionTargetAndStartingView() { + targetView.frame = CGRect(x: targetCoordinateX - targetHorizontalOffset, y: targetCoordinateY - targetVerticalOffset, width: targetWidth, height: targetHeight) + startingMarkerView.frame = CGRect(x: centerX - targetHorizontalOffset, y: centerY - targetVerticalOffset, width: targetWidth, height: targetHeight) + } + + func containsPoint(x: CGFloat, y: CGFloat) -> Bool { + return abs(Int(x) - targetCoordinateX) < targetHorizontalOffset && abs(Int(y) - targetCoordinateY) < targetHorizontalOffset + } + + + + static func readFromFile() -> (Int, Int) { + guard let dictionary = NSDictionary(contentsOfFile: path), x = dictionary["x"] as? NSNumber, y = dictionary["y"] as? NSNumber else { + Target.writeToFile(x: 8 * targetWidth, y: 3 * targetHeight) + return (8 * targetWidth, 3 * targetHeight) + } + return (x.integerValue, y.integerValue) + + } + + static func writeToFile(x x: Int, y: Int) { + let dictionary = ["x" : x, "y" : y] as NSDictionary + dictionary.writeToFile(Target.path, atomically: true) + } + + + func resetTarget() -> Target { + let source = GKARC4RandomSource() + source.dropValuesWithCount(1000) + let distribution = GKShuffledDistribution(lowestValue: 1, highestValue: 11) + let x = distribution.nextInt() * targetWidth + let y = distribution.nextInt() * targetHeight + Target.writeToFile(x: x, y: y) + return Target(targetCoordinateX: x, targetCoordinateY: y) +} + + + + +} diff --git a/Turtle.playground/Pages/Cosmic Turtle and Target.xcplaygroundpage/Sources/Secret Turtle Stuff/Turtle.swift b/Turtle.playground/Pages/Cosmic Turtle and Target.xcplaygroundpage/Sources/Secret Turtle Stuff/Turtle.swift new file mode 100644 index 0000000..2a6a607 --- /dev/null +++ b/Turtle.playground/Pages/Cosmic Turtle and Target.xcplaygroundpage/Sources/Secret Turtle Stuff/Turtle.swift @@ -0,0 +1,82 @@ +import UIKit + +public private(set) var turtle = Turtle() + + +public struct Turtle { + + private var currentPath: Path + public let view: TurtleView + private var avatar: Avatar + private let target: Target + + // MARK: - Initializers + + public init() { + let terrariumFrame = CGRect(x: 0, y: 0, width: width, height: height) + avatar = Avatar() + view = TurtleView(frame: terrariumFrame, avatarView: avatar.view) + currentPath = Path(startingPoint: CGPoint(x: centerX , y: centerY)) + target = Target() + view.addPath(currentPath) + view.addSubview(target.targetView) + view.addSubview(target.startingMarkerView) + updateAvatar() + } + private init(currentPath: Path, view: TurtleView, avatar: Avatar, target: Target){ + self.currentPath = currentPath + self.view = view + self.avatar = avatar + self.target = target + updateAvatar() + } + + // MARK: - Position + + func forward(distance: Double) { + let path = currentPath.forward(distance, inDirection: avatar.headingInRadians) + turtle = Turtle(currentPath: path, view: view, avatar: avatar, target: target) + if target.containsPoint(path.currentPoint.x, y: path.currentPoint.y) { + view.backgroundColor = victoryColor + } else { + view.backgroundColor = environmentColor + } + } + + // MARK: - Colors + + func penColor(penColor: PenColor) { + let path = Path(startingPoint:currentPath.currentPoint, penColor: penColor ) + view.addPath(path) + turtle = Turtle(currentPath: path, view: view, avatar: avatar.penColor(penColor), target: target) + + } + func nextColor() { + penColor(currentPath.penColor.next()) + } + + // MARK: - Direction + + func increaseHeadingBy(degrees: Double) { + turtle = Turtle(currentPath: currentPath, view: view, avatar: avatar.increaseHeadingBy(degrees), target: target) + + } + + + // MARK: Utility + + private func updateAvatar() { + view.updateAvatarTransform(avatar.positionTransform(currentPath.currentPoint)) + } + func resetTarget() { + turtle = Turtle(currentPath: currentPath, view: view, avatar: avatar, target: target.resetTarget()) + } +} + +extension Turtle: CustomPlaygroundQuickLookable { + public func customPlaygroundQuickLook() -> PlaygroundQuickLook { + + return PlaygroundQuickLook(reflecting: view) + } + +} diff --git a/Turtle.playground/Pages/Cosmic Turtle and Target.xcplaygroundpage/Sources/Secret Turtle Stuff/TurtleView.swift b/Turtle.playground/Pages/Cosmic Turtle and Target.xcplaygroundpage/Sources/Secret Turtle Stuff/TurtleView.swift new file mode 100644 index 0000000..8603381 --- /dev/null +++ b/Turtle.playground/Pages/Cosmic Turtle and Target.xcplaygroundpage/Sources/Secret Turtle Stuff/TurtleView.swift @@ -0,0 +1,34 @@ +import UIKit +import CoreGraphics + + +public class TurtleView: UIView { + private var paths = [Path]() + private var avatarView = UIImageView() + + + // MARK: Initializers + init(frame: CGRect, avatarView: UIImageView) { + super.init(frame: frame) + self.avatarView = avatarView + backgroundColor = environmentColor + addSubview(avatarView) + } + required public init?(coder aDecoder: NSCoder) { + super.init(coder:aDecoder) + } + + // MARK: Draw Methods + override public func drawRect(rect: CGRect) { + for path in paths { + path.penColor.color.setStroke() + path.bezierPath.stroke() + } + } + func addPath(path:Path) { + paths.append(path) + } + func updateAvatarTransform(transform: CGAffineTransform) { + avatarView.transform = transform + } +} \ No newline at end of file diff --git a/Turtle.playground/Pages/Cosmic Turtle and Target.xcplaygroundpage/Sources/TurtleCommands.swift b/Turtle.playground/Pages/Cosmic Turtle and Target.xcplaygroundpage/Sources/TurtleCommands.swift new file mode 100644 index 0000000..e498d83 --- /dev/null +++ b/Turtle.playground/Pages/Cosmic Turtle and Target.xcplaygroundpage/Sources/TurtleCommands.swift @@ -0,0 +1,26 @@ +public func forward(distance: Int = standardForwardDistance) { + turtle.forward(Double(distance)) +} + +public func back(distance: Int = standardForwardDistance) { + turtle.forward(Double(-distance)) +} + +public func right(angle: Int = rightAngle) { + turtle.increaseHeadingBy(Double(angle)) +} +public func left(angle: Int = rightAngle) { + turtle.increaseHeadingBy(Double(-angle)) +} + +public func penColor(penColor:PenColor){ + turtle.penColor(penColor) +} + +public func nextColor() { + turtle.nextColor() +} + +public func resetTarget() { + turtle.resetTarget() +} \ No newline at end of file diff --git a/Turtle.playground/Pages/Linear Turtle with Target Hint.xcplaygroundpage/Contents.swift b/Turtle.playground/Pages/Linear Turtle with Target Hint.xcplaygroundpage/Contents.swift new file mode 100644 index 0000000..9629e5e --- /dev/null +++ b/Turtle.playground/Pages/Linear Turtle with Target Hint.xcplaygroundpage/Contents.swift @@ -0,0 +1,10 @@ +/*: +### Linear Turtle with Target Hints + +[Back](Linear%20Turtle%20with%20Target) + +--- +* We begin with a turtle who knows how to move `forward()` and `back()` +* Can you steer the turtle to the target? +* To reset the target, remove the turtle and type resetTarget() +*/ diff --git a/Turtle.playground/Pages/Linear Turtle with Target.xcplaygroundpage/Contents.swift b/Turtle.playground/Pages/Linear Turtle with Target.xcplaygroundpage/Contents.swift new file mode 100644 index 0000000..9197c70 --- /dev/null +++ b/Turtle.playground/Pages/Linear Turtle with Target.xcplaygroundpage/Contents.swift @@ -0,0 +1,7 @@ +/*: +### Linear Turtle with Target ([Hint](Linear%20Turtle%20with%20Target%20Hint)) + +[TOC](Contents) | [Previous](@previous) | [Next](@next) + +--- +*/ diff --git a/Turtle.playground/Pages/Linear Turtle with Target.xcplaygroundpage/Resources/Readme b/Turtle.playground/Pages/Linear Turtle with Target.xcplaygroundpage/Resources/Readme new file mode 100644 index 0000000..fb93ee9 --- /dev/null +++ b/Turtle.playground/Pages/Linear Turtle with Target.xcplaygroundpage/Resources/Readme @@ -0,0 +1,4 @@ +Linear Turtle with Target + +We begin with a turtle that can move forward() and back(). + diff --git a/Turtle.playground/Pages/Linear Turtle with Target.xcplaygroundpage/Resources/RightArrow.png b/Turtle.playground/Pages/Linear Turtle with Target.xcplaygroundpage/Resources/RightArrow.png new file mode 100644 index 0000000..f3ec19f Binary files /dev/null and b/Turtle.playground/Pages/Linear Turtle with Target.xcplaygroundpage/Resources/RightArrow.png differ diff --git a/Turtle.playground/Pages/Linear Turtle with Target.xcplaygroundpage/Resources/Target.png b/Turtle.playground/Pages/Linear Turtle with Target.xcplaygroundpage/Resources/Target.png new file mode 100644 index 0000000..cb3c7c2 Binary files /dev/null and b/Turtle.playground/Pages/Linear Turtle with Target.xcplaygroundpage/Resources/Target.png differ diff --git a/Turtle.playground/Pages/Linear Turtle with Target.xcplaygroundpage/Resources/Turtle.png b/Turtle.playground/Pages/Linear Turtle with Target.xcplaygroundpage/Resources/Turtle.png new file mode 100644 index 0000000..11d3e16 Binary files /dev/null and b/Turtle.playground/Pages/Linear Turtle with Target.xcplaygroundpage/Resources/Turtle.png differ diff --git a/Turtle.playground/Pages/Linear Turtle with Target.xcplaygroundpage/Sources/Secret Turtle Stuff/Avatar.swift b/Turtle.playground/Pages/Linear Turtle with Target.xcplaygroundpage/Sources/Secret Turtle Stuff/Avatar.swift new file mode 100644 index 0000000..3f61ab3 --- /dev/null +++ b/Turtle.playground/Pages/Linear Turtle with Target.xcplaygroundpage/Sources/Secret Turtle Stuff/Avatar.swift @@ -0,0 +1,34 @@ +import UIKit + +struct Avatar { + private(set) var view = UIImageView() + private(set) var headingInRadians = 0.0 + private let image: UIImage + + // MARK: - Initializers + + init(){ + image = UIImage(named: "Turtle.png")! + view = UIImageView(image: image) + } + + private init(view: UIImageView, image: UIImage, headingInRadians: Double) { + self.view = view + self.headingInRadians = headingInRadians + self.image = image + } + + + // MARK: - Position + + func positionTransform(currentPoint: CGPoint) -> CGAffineTransform { + let rotateByRadians = CGAffineTransformMakeRotation(CGFloat(headingInRadians)) + let centerOfTurtleX = currentPoint.x - view.center.x + let centerOfTurtleY = currentPoint.y - view.center.y + let moveTurtle = CGAffineTransformMakeTranslation(centerOfTurtleX, centerOfTurtleY) + let turtleTransform = CGAffineTransformConcat(rotateByRadians, moveTurtle) + return turtleTransform + } + + +} \ No newline at end of file diff --git a/Turtle.playground/Pages/Linear Turtle with Target.xcplaygroundpage/Sources/Secret Turtle Stuff/Constants.swift b/Turtle.playground/Pages/Linear Turtle with Target.xcplaygroundpage/Sources/Secret Turtle Stuff/Constants.swift new file mode 100644 index 0000000..a571853 --- /dev/null +++ b/Turtle.playground/Pages/Linear Turtle with Target.xcplaygroundpage/Sources/Secret Turtle Stuff/Constants.swift @@ -0,0 +1,26 @@ +import UIKit + +let centerX = 300 +let centerY = 300 +let width = 2 * centerX +let height = 2 * centerY +let terrarium = CGRect(x: 0, y: 0, width: width, height: height) + +let lineWidth: CGFloat = 4.0 + +private let targetOffset = 25 +let targetHorizontalOffset = targetOffset +let targetVerticalOffset = targetOffset +let targetSteps = 11 + +let targetWidth = 2 * targetHorizontalOffset +let targetHeight = 2 * targetVerticalOffset + +let standardForwardDistance = 2 * targetOffset + +let environmentColor = UIColor(red: 0.2, + green: 1.0, + blue: 1.0, + alpha: 0.1) +let penColor = UIColor.blackColor() +let victoryColor = UIColor.yellowColor() diff --git a/Turtle.playground/Pages/Linear Turtle with Target.xcplaygroundpage/Sources/Secret Turtle Stuff/Path.swift b/Turtle.playground/Pages/Linear Turtle with Target.xcplaygroundpage/Sources/Secret Turtle Stuff/Path.swift new file mode 100644 index 0000000..3f3d52e --- /dev/null +++ b/Turtle.playground/Pages/Linear Turtle with Target.xcplaygroundpage/Sources/Secret Turtle Stuff/Path.swift @@ -0,0 +1,36 @@ +import UIKit + +struct Path { + var bezierPath = UIBezierPath() + var currentPoint: CGPoint { + return bezierPath.currentPoint + } + + // MARK: - Initializers + + init(startingPoint: CGPoint) { + bezierPath.moveToPoint(startingPoint) + bezierPath.lineWidth = lineWidth + } + + private init(bezierPath: UIBezierPath) { + self.bezierPath = bezierPath + } + + // MARK: - Position + + func moveTo(x x:Double, y: Double) -> Path { + bezierPath.addLineToPoint(CGPoint(x: x, y: y)) + return Path(bezierPath: bezierPath) + } + + func forward(distance: Double, inDirection headingInRadians: Double) -> Path { + let dx = distance * cos(headingInRadians) + let dy = distance * sin(headingInRadians) + let currentX = Double(bezierPath.currentPoint.x) + let currentY = Double(bezierPath.currentPoint.y) + return moveTo(x: currentX + dx, y: currentY + dy) + } + +} + diff --git a/Turtle.playground/Pages/Linear Turtle with Target.xcplaygroundpage/Sources/Secret Turtle Stuff/TargetView.swift b/Turtle.playground/Pages/Linear Turtle with Target.xcplaygroundpage/Sources/Secret Turtle Stuff/TargetView.swift new file mode 100644 index 0000000..e0be6e1 --- /dev/null +++ b/Turtle.playground/Pages/Linear Turtle with Target.xcplaygroundpage/Sources/Secret Turtle Stuff/TargetView.swift @@ -0,0 +1,61 @@ +import UIKit +import XCPlayground +import GameKit + +struct Target { + static private let path = (XCPSharedDataDirectoryPath as NSString).stringByAppendingPathComponent("LinearTarget.plist") + let targetView = UIImageView(image: UIImage(named: "Target.png")) + let startingMarkerView = UIImageView(image: UIImage(named: "RightArrow.png")) + let targetCoordinateX: Int + let targetCoordinateY: Int + + init() { + (targetCoordinateX, targetCoordinateY) = Target.readFromFile() + positionTargetAndStartingView() + } + private init(targetCoordinateX: Int, targetCoordinateY: Int) { + self.targetCoordinateX = targetCoordinateX + self.targetCoordinateY = targetCoordinateY + positionTargetAndStartingView() + } + + func positionTargetAndStartingView() { + targetView.frame = CGRect(x: targetCoordinateX - targetHorizontalOffset, y: targetCoordinateY - targetVerticalOffset, width: targetWidth, height: targetHeight) + startingMarkerView.frame = CGRect(x: centerX - targetHorizontalOffset, y: centerY - targetVerticalOffset, width: targetWidth, height: targetHeight) + } + + func containsPoint(x: CGFloat, y: CGFloat) -> Bool { + return abs(Int(x) - targetCoordinateX) < targetHorizontalOffset && abs(Int(y) - targetCoordinateY) < targetHorizontalOffset + } + + + + static func readFromFile() -> (Int, Int) { + guard let dictionary = NSDictionary(contentsOfFile: path), x = dictionary["x"] as? NSNumber, y = dictionary["y"] as? NSNumber else { + Target.writeToFile(x: 8 * targetWidth, y: centerY) + return (8 * targetWidth, centerY) + } + return (x.integerValue, y.integerValue) + + } + + static func writeToFile(x x: Int, y: Int) { + let dictionary = ["x" : x, "y" : y] as NSDictionary + dictionary.writeToFile(Target.path, atomically: true) + } + + + func resetTarget() -> Target { + let source = GKARC4RandomSource() + source.dropValuesWithCount(1000) + let distribution = GKShuffledDistribution(lowestValue: 1, highestValue: 11) + let x = distribution.nextInt() * targetWidth + let y = centerY + Target.writeToFile(x: x, y: y) + return Target(targetCoordinateX: x, targetCoordinateY: y) +} + + + + +} diff --git a/Turtle.playground/Pages/Linear Turtle with Target.xcplaygroundpage/Sources/Secret Turtle Stuff/Turtle.swift b/Turtle.playground/Pages/Linear Turtle with Target.xcplaygroundpage/Sources/Secret Turtle Stuff/Turtle.swift new file mode 100644 index 0000000..35ed408 --- /dev/null +++ b/Turtle.playground/Pages/Linear Turtle with Target.xcplaygroundpage/Sources/Secret Turtle Stuff/Turtle.swift @@ -0,0 +1,64 @@ +import UIKit + +public private(set) var turtle = Turtle() + + +public struct Turtle { + + private var currentPath: Path + public let view: TurtleView + private var avatar: Avatar + private let target: Target + + // MARK: - Initializers + + public init() { + let terrariumFrame = CGRect(x: 0, y: 0, width: width, height: height) + avatar = Avatar() + view = TurtleView(frame: terrariumFrame, avatarView: avatar.view) + currentPath = Path(startingPoint: CGPoint(x: centerX , y: centerY)) + target = Target() + view.addPath(currentPath) + view.addSubview(target.targetView) + view.addSubview(target.startingMarkerView) + updateAvatar() + } + private init(currentPath: Path, view: TurtleView, avatar: Avatar, target: Target){ + self.currentPath = currentPath + self.view = view + self.avatar = avatar + self.target = target + updateAvatar() + } + + // MARK: - Position + + func forward(distance: Double) { + let path = currentPath.forward(distance, inDirection: avatar.headingInRadians) + turtle = Turtle(currentPath: path, view: view, avatar: avatar, target: target) + if target.containsPoint(path.currentPoint.x, y: path.currentPoint.y) { + view.backgroundColor = victoryColor + } else { + view.backgroundColor = environmentColor + } + + } + + + // MARK: Utility + + private func updateAvatar() { + view.updateAvatarTransform(avatar.positionTransform(currentPath.currentPoint)) + } + func resetTarget() { + turtle = Turtle(currentPath: currentPath, view: view, avatar: avatar, target: target.resetTarget()) + } +} + +extension Turtle: CustomPlaygroundQuickLookable { + public func customPlaygroundQuickLook() -> PlaygroundQuickLook { + + return PlaygroundQuickLook(reflecting: view) + } + +} diff --git a/Turtle.playground/Pages/Linear Turtle with Target.xcplaygroundpage/Sources/Secret Turtle Stuff/TurtleView.swift b/Turtle.playground/Pages/Linear Turtle with Target.xcplaygroundpage/Sources/Secret Turtle Stuff/TurtleView.swift new file mode 100644 index 0000000..e9d26a2 --- /dev/null +++ b/Turtle.playground/Pages/Linear Turtle with Target.xcplaygroundpage/Sources/Secret Turtle Stuff/TurtleView.swift @@ -0,0 +1,34 @@ +import UIKit +import CoreGraphics + + +public class TurtleView: UIView { + private var paths = [Path]() + private var avatarView = UIImageView() + + + // MARK: Initializers + init(frame: CGRect, avatarView: UIImageView) { + super.init(frame: frame) + self.avatarView = avatarView + backgroundColor = environmentColor + addSubview(avatarView) + } + required public init?(coder aDecoder: NSCoder) { + super.init(coder:aDecoder) + } + + // MARK: Draw Methods + override public func drawRect(rect: CGRect) { + for path in paths { + penColor.setStroke() + path.bezierPath.stroke() + } + } + func addPath(path:Path) { + paths.append(path) + } + func updateAvatarTransform(transform: CGAffineTransform) { + avatarView.transform = transform + } +} \ No newline at end of file diff --git a/Turtle.playground/Pages/Linear Turtle with Target.xcplaygroundpage/Sources/TurtleCommands.swift b/Turtle.playground/Pages/Linear Turtle with Target.xcplaygroundpage/Sources/TurtleCommands.swift new file mode 100644 index 0000000..ca2afe4 --- /dev/null +++ b/Turtle.playground/Pages/Linear Turtle with Target.xcplaygroundpage/Sources/TurtleCommands.swift @@ -0,0 +1,11 @@ +public func forward() { + turtle.forward(Double(standardForwardDistance)) +} + +public func back() { + turtle.forward(Double(-standardForwardDistance)) +} + +public func resetTarget() { + turtle.resetTarget() +} \ No newline at end of file diff --git a/Turtle.playground/Pages/Turtle Hint.xcplaygroundpage/Contents.swift b/Turtle.playground/Pages/Turtle Hint.xcplaygroundpage/Contents.swift new file mode 100644 index 0000000..109dd1e --- /dev/null +++ b/Turtle.playground/Pages/Turtle Hint.xcplaygroundpage/Contents.swift @@ -0,0 +1,10 @@ +/*: +### Turtle Hints + +[Back](Turtle) + +--- +* You can now `show()` and `hide()` the turtle. +* You can also raise and lower the pen using `penUp()` and `penDown()`. +* You can `moveTo()` to a location, set your `heading()` and reset the turtle by moving it `home()`. +*/ diff --git a/Turtle.playground/Pages/Turtle with Parameters and Target Hint.xcplaygroundpage/Contents.swift b/Turtle.playground/Pages/Turtle with Parameters and Target Hint.xcplaygroundpage/Contents.swift new file mode 100644 index 0000000..08c9d78 --- /dev/null +++ b/Turtle.playground/Pages/Turtle with Parameters and Target Hint.xcplaygroundpage/Contents.swift @@ -0,0 +1,9 @@ +/*: +### Turtle with Parameters and Target Hints + +[Back](Turtle%20with%20Parameters%20and%20Target) + +--- +* The `forward()` and `back()` functions can accept parameters that tell us how far to move. The default amount is 50. +* Similarly `right()` and `left()` can accept parameters describing the angle to turn. The default value is 90. +*/ diff --git a/Turtle.playground/Pages/Turtle with Parameters and Target.xcplaygroundpage/Contents.swift b/Turtle.playground/Pages/Turtle with Parameters and Target.xcplaygroundpage/Contents.swift new file mode 100644 index 0000000..e3ab619 --- /dev/null +++ b/Turtle.playground/Pages/Turtle with Parameters and Target.xcplaygroundpage/Contents.swift @@ -0,0 +1,8 @@ +/*: +### Turtle with Target and Parameters ([Hint](Turtle%20with%20Parameters%20and%20Target%20Hint)) + +[TOC](Contents) | [Previous](@previous) | [Next](@next) + +--- +*/ + diff --git a/Turtle.playground/Pages/Turtle with Parameters and Target.xcplaygroundpage/Resources/RightArrow.png b/Turtle.playground/Pages/Turtle with Parameters and Target.xcplaygroundpage/Resources/RightArrow.png new file mode 100644 index 0000000..f3ec19f Binary files /dev/null and b/Turtle.playground/Pages/Turtle with Parameters and Target.xcplaygroundpage/Resources/RightArrow.png differ diff --git a/Turtle.playground/Pages/Turtle with Parameters and Target.xcplaygroundpage/Resources/Target.png b/Turtle.playground/Pages/Turtle with Parameters and Target.xcplaygroundpage/Resources/Target.png new file mode 100644 index 0000000..cb3c7c2 Binary files /dev/null and b/Turtle.playground/Pages/Turtle with Parameters and Target.xcplaygroundpage/Resources/Target.png differ diff --git a/Turtle.playground/Pages/Turtle with Parameters and Target.xcplaygroundpage/Resources/Turtle.png b/Turtle.playground/Pages/Turtle with Parameters and Target.xcplaygroundpage/Resources/Turtle.png new file mode 100644 index 0000000..11d3e16 Binary files /dev/null and b/Turtle.playground/Pages/Turtle with Parameters and Target.xcplaygroundpage/Resources/Turtle.png differ diff --git a/Turtle.playground/Pages/Turtle with Parameters and Target.xcplaygroundpage/Sources/Secret Turtle Stuff/Avatar.swift b/Turtle.playground/Pages/Turtle with Parameters and Target.xcplaygroundpage/Sources/Secret Turtle Stuff/Avatar.swift new file mode 100644 index 0000000..c48ae4c --- /dev/null +++ b/Turtle.playground/Pages/Turtle with Parameters and Target.xcplaygroundpage/Sources/Secret Turtle Stuff/Avatar.swift @@ -0,0 +1,40 @@ +import UIKit + +struct Avatar { + private(set) var view = UIImageView() + private(set) var headingInRadians = 0.0 + private let image: UIImage + + // MARK: - Initializers + + init(){ + image = UIImage(named: "Turtle.png")! + view = UIImageView(image: image) + } + + private init(view: UIImageView, image: UIImage, headingInRadians: Double) { + self.view = view + self.headingInRadians = headingInRadians + self.image = image + } + + // MARK: - Direction + + func increaseHeadingBy(degrees: Double) -> Avatar { + return Avatar(view: view, image: image, headingInRadians: headingInRadians + degrees/180 * M_PI ) + } + + + // MARK: - Position + + func positionTransform(currentPoint: CGPoint) -> CGAffineTransform { + let rotateByRadians = CGAffineTransformMakeRotation(CGFloat(headingInRadians)) + let centerOfTurtleX = currentPoint.x - view.center.x + let centerOfTurtleY = currentPoint.y - view.center.y + let moveTurtle = CGAffineTransformMakeTranslation(centerOfTurtleX, centerOfTurtleY) + let turtleTransform = CGAffineTransformConcat(rotateByRadians, moveTurtle) + return turtleTransform + } + + +} \ No newline at end of file diff --git a/Turtle.playground/Pages/Turtle with Parameters and Target.xcplaygroundpage/Sources/Secret Turtle Stuff/Constants.swift b/Turtle.playground/Pages/Turtle with Parameters and Target.xcplaygroundpage/Sources/Secret Turtle Stuff/Constants.swift new file mode 100644 index 0000000..4c7a6e3 --- /dev/null +++ b/Turtle.playground/Pages/Turtle with Parameters and Target.xcplaygroundpage/Sources/Secret Turtle Stuff/Constants.swift @@ -0,0 +1,27 @@ +import UIKit + +let centerX = 300 +let centerY = 300 +let width = 2 * centerX +let height = 2 * centerY +let terrarium = CGRect(x: 0, y: 0, width: width, height: height) + +let lineWidth: CGFloat = 4.0 + +private let targetOffset = 25 +let targetHorizontalOffset = targetOffset +let targetVerticalOffset = targetOffset +let targetSteps = 11 + +let targetWidth = 2 * targetHorizontalOffset +let targetHeight = 2 * targetVerticalOffset + +let standardForwardDistance = 2 * targetOffset +let rightAngle = 90 + +let environmentColor = UIColor(red: 0.2, + green: 1.0, + blue: 1.0, + alpha: 0.1) +let penColor = UIColor.blackColor() +let victoryColor = UIColor.yellowColor() diff --git a/Turtle.playground/Pages/Turtle with Parameters and Target.xcplaygroundpage/Sources/Secret Turtle Stuff/Path.swift b/Turtle.playground/Pages/Turtle with Parameters and Target.xcplaygroundpage/Sources/Secret Turtle Stuff/Path.swift new file mode 100644 index 0000000..3f3d52e --- /dev/null +++ b/Turtle.playground/Pages/Turtle with Parameters and Target.xcplaygroundpage/Sources/Secret Turtle Stuff/Path.swift @@ -0,0 +1,36 @@ +import UIKit + +struct Path { + var bezierPath = UIBezierPath() + var currentPoint: CGPoint { + return bezierPath.currentPoint + } + + // MARK: - Initializers + + init(startingPoint: CGPoint) { + bezierPath.moveToPoint(startingPoint) + bezierPath.lineWidth = lineWidth + } + + private init(bezierPath: UIBezierPath) { + self.bezierPath = bezierPath + } + + // MARK: - Position + + func moveTo(x x:Double, y: Double) -> Path { + bezierPath.addLineToPoint(CGPoint(x: x, y: y)) + return Path(bezierPath: bezierPath) + } + + func forward(distance: Double, inDirection headingInRadians: Double) -> Path { + let dx = distance * cos(headingInRadians) + let dy = distance * sin(headingInRadians) + let currentX = Double(bezierPath.currentPoint.x) + let currentY = Double(bezierPath.currentPoint.y) + return moveTo(x: currentX + dx, y: currentY + dy) + } + +} + diff --git a/Turtle.playground/Pages/Turtle with Parameters and Target.xcplaygroundpage/Sources/Secret Turtle Stuff/TargetView.swift b/Turtle.playground/Pages/Turtle with Parameters and Target.xcplaygroundpage/Sources/Secret Turtle Stuff/TargetView.swift new file mode 100644 index 0000000..717903c --- /dev/null +++ b/Turtle.playground/Pages/Turtle with Parameters and Target.xcplaygroundpage/Sources/Secret Turtle Stuff/TargetView.swift @@ -0,0 +1,61 @@ +import UIKit +import XCPlayground +import GameKit + +struct Target { + static private let path = (XCPSharedDataDirectoryPath as NSString).stringByAppendingPathComponent("Target.plist") + let targetView = UIImageView(image: UIImage(named: "Target.png")) + let startingMarkerView = UIImageView(image: UIImage(named: "RightArrow.png")) + let targetCoordinateX: Int + let targetCoordinateY: Int + + init() { + (targetCoordinateX, targetCoordinateY) = Target.readFromFile() + positionTargetAndStartingView() + } + private init(targetCoordinateX: Int, targetCoordinateY: Int) { + self.targetCoordinateX = targetCoordinateX + self.targetCoordinateY = targetCoordinateY + positionTargetAndStartingView() + } + + func positionTargetAndStartingView() { + targetView.frame = CGRect(x: targetCoordinateX - targetHorizontalOffset, y: targetCoordinateY - targetVerticalOffset, width: targetWidth, height: targetHeight) + startingMarkerView.frame = CGRect(x: centerX - targetHorizontalOffset, y: centerY - targetVerticalOffset, width: targetWidth, height: targetHeight) + } + + func containsPoint(x: CGFloat, y: CGFloat) -> Bool { + return abs(Int(x) - targetCoordinateX) < targetHorizontalOffset && abs(Int(y) - targetCoordinateY) < targetHorizontalOffset + } + + + + static func readFromFile() -> (Int, Int) { + guard let dictionary = NSDictionary(contentsOfFile: path), x = dictionary["x"] as? NSNumber, y = dictionary["y"] as? NSNumber else { + Target.writeToFile(x: 8 * targetWidth, y: 3 * targetHeight) + return (8 * targetWidth, 3 * targetHeight) + } + return (x.integerValue, y.integerValue) + + } + + static func writeToFile(x x: Int, y: Int) { + let dictionary = ["x" : x, "y" : y] as NSDictionary + dictionary.writeToFile(Target.path, atomically: true) + } + + + func resetTarget() -> Target { + let source = GKARC4RandomSource() + source.dropValuesWithCount(1000) + let distribution = GKShuffledDistribution(lowestValue: 1, highestValue: 11) + let x = distribution.nextInt() * targetWidth + let y = distribution.nextInt() * targetHeight + Target.writeToFile(x: x, y: y) + return Target(targetCoordinateX: x, targetCoordinateY: y) +} + + + + +} diff --git a/Turtle.playground/Pages/Turtle with Parameters and Target.xcplaygroundpage/Sources/Secret Turtle Stuff/Turtle.swift b/Turtle.playground/Pages/Turtle with Parameters and Target.xcplaygroundpage/Sources/Secret Turtle Stuff/Turtle.swift new file mode 100644 index 0000000..c25d982 --- /dev/null +++ b/Turtle.playground/Pages/Turtle with Parameters and Target.xcplaygroundpage/Sources/Secret Turtle Stuff/Turtle.swift @@ -0,0 +1,72 @@ +import UIKit + +public private(set) var turtle = Turtle() + + +public struct Turtle { + + private var currentPath: Path + public let view: TurtleView + private var avatar: Avatar + private let target: Target + + // MARK: - Initializers + + public init() { + let terrariumFrame = CGRect(x: 0, y: 0, width: width, height: height) + avatar = Avatar() + view = TurtleView(frame: terrariumFrame, avatarView: avatar.view) + currentPath = Path(startingPoint: CGPoint(x: centerX , y: centerY)) + target = Target() + view.addPath(currentPath) + view.addSubview(target.targetView) + view.addSubview(target.startingMarkerView) + updateAvatar() + } + private init(currentPath: Path, view: TurtleView, avatar: Avatar, target: Target){ + self.currentPath = currentPath + self.view = view + self.avatar = avatar + self.target = target + updateAvatar() + } + + // MARK: - Position + + func forward(distance: Double) { + let path = currentPath.forward(distance, inDirection: avatar.headingInRadians) + turtle = Turtle(currentPath: path, view: view, avatar: avatar, target: target) + if target.containsPoint(path.currentPoint.x, y: path.currentPoint.y) { + view.backgroundColor = victoryColor + } else { + view.backgroundColor = environmentColor + } + + } + + + // MARK: - Direction + + func increaseHeadingBy(degrees: Double) { + turtle = Turtle(currentPath: currentPath, view: view, avatar: avatar.increaseHeadingBy(degrees), target: target) + + } + + + // MARK: Utility + + private func updateAvatar() { + view.updateAvatarTransform(avatar.positionTransform(currentPath.currentPoint)) + } + func resetTarget() { + turtle = Turtle(currentPath: currentPath, view: view, avatar: avatar, target: target.resetTarget()) + } +} + +extension Turtle: CustomPlaygroundQuickLookable { + public func customPlaygroundQuickLook() -> PlaygroundQuickLook { + + return PlaygroundQuickLook(reflecting: view) + } + +} diff --git a/Turtle.playground/Pages/Turtle with Parameters and Target.xcplaygroundpage/Sources/Secret Turtle Stuff/TurtleView.swift b/Turtle.playground/Pages/Turtle with Parameters and Target.xcplaygroundpage/Sources/Secret Turtle Stuff/TurtleView.swift new file mode 100644 index 0000000..e9d26a2 --- /dev/null +++ b/Turtle.playground/Pages/Turtle with Parameters and Target.xcplaygroundpage/Sources/Secret Turtle Stuff/TurtleView.swift @@ -0,0 +1,34 @@ +import UIKit +import CoreGraphics + + +public class TurtleView: UIView { + private var paths = [Path]() + private var avatarView = UIImageView() + + + // MARK: Initializers + init(frame: CGRect, avatarView: UIImageView) { + super.init(frame: frame) + self.avatarView = avatarView + backgroundColor = environmentColor + addSubview(avatarView) + } + required public init?(coder aDecoder: NSCoder) { + super.init(coder:aDecoder) + } + + // MARK: Draw Methods + override public func drawRect(rect: CGRect) { + for path in paths { + penColor.setStroke() + path.bezierPath.stroke() + } + } + func addPath(path:Path) { + paths.append(path) + } + func updateAvatarTransform(transform: CGAffineTransform) { + avatarView.transform = transform + } +} \ No newline at end of file diff --git a/Turtle.playground/Pages/Turtle with Parameters and Target.xcplaygroundpage/Sources/TurtleCommands.swift b/Turtle.playground/Pages/Turtle with Parameters and Target.xcplaygroundpage/Sources/TurtleCommands.swift new file mode 100644 index 0000000..4aae68f --- /dev/null +++ b/Turtle.playground/Pages/Turtle with Parameters and Target.xcplaygroundpage/Sources/TurtleCommands.swift @@ -0,0 +1,18 @@ +public func forward(distance: Int = standardForwardDistance) { + turtle.forward(Double(distance)) +} + +public func back(distance: Int = standardForwardDistance) { + turtle.forward(Double(-distance)) +} + +public func right(angle: Int = rightAngle) { + turtle.increaseHeadingBy(Double(angle)) +} +public func left(angle: Int = rightAngle) { + turtle.increaseHeadingBy(Double(-angle)) +} + +public func resetTarget() { + turtle.resetTarget() +} \ No newline at end of file diff --git a/Turtle.playground/Pages/Turtle with Target Hint.xcplaygroundpage/Contents.swift b/Turtle.playground/Pages/Turtle with Target Hint.xcplaygroundpage/Contents.swift new file mode 100644 index 0000000..c255644 --- /dev/null +++ b/Turtle.playground/Pages/Turtle with Target Hint.xcplaygroundpage/Contents.swift @@ -0,0 +1,9 @@ +/*: +### Turtle with Target Hints + +[Back](Turtle%20with%20Target) + +--- +* Next we add the ability to turn our turtle `right()` and `left()` +* Can you steer the turtle to a target that isn't directly in front of or behind our turtle? +*/ diff --git a/Turtle.playground/Pages/Turtle with Target.xcplaygroundpage/Contents.swift b/Turtle.playground/Pages/Turtle with Target.xcplaygroundpage/Contents.swift new file mode 100644 index 0000000..4e91ed8 --- /dev/null +++ b/Turtle.playground/Pages/Turtle with Target.xcplaygroundpage/Contents.swift @@ -0,0 +1,7 @@ +/*: +### Turtle with Target ([Hint](Turtle%20with%20Target%20Hint)) + +[TOC](Contents) | [Previous](@previous) | [Next](@next) + +--- +*/ diff --git a/Turtle.playground/Pages/Turtle with Target.xcplaygroundpage/Resources/RightArrow.png b/Turtle.playground/Pages/Turtle with Target.xcplaygroundpage/Resources/RightArrow.png new file mode 100644 index 0000000..f3ec19f Binary files /dev/null and b/Turtle.playground/Pages/Turtle with Target.xcplaygroundpage/Resources/RightArrow.png differ diff --git a/Turtle.playground/Pages/Turtle with Target.xcplaygroundpage/Resources/Target.png b/Turtle.playground/Pages/Turtle with Target.xcplaygroundpage/Resources/Target.png new file mode 100644 index 0000000..cb3c7c2 Binary files /dev/null and b/Turtle.playground/Pages/Turtle with Target.xcplaygroundpage/Resources/Target.png differ diff --git a/Turtle.playground/Pages/Turtle with Target.xcplaygroundpage/Resources/Turtle.png b/Turtle.playground/Pages/Turtle with Target.xcplaygroundpage/Resources/Turtle.png new file mode 100644 index 0000000..11d3e16 Binary files /dev/null and b/Turtle.playground/Pages/Turtle with Target.xcplaygroundpage/Resources/Turtle.png differ diff --git a/Turtle.playground/Pages/Turtle with Target.xcplaygroundpage/Sources/Secret Turtle Stuff/Avatar.swift b/Turtle.playground/Pages/Turtle with Target.xcplaygroundpage/Sources/Secret Turtle Stuff/Avatar.swift new file mode 100644 index 0000000..c48ae4c --- /dev/null +++ b/Turtle.playground/Pages/Turtle with Target.xcplaygroundpage/Sources/Secret Turtle Stuff/Avatar.swift @@ -0,0 +1,40 @@ +import UIKit + +struct Avatar { + private(set) var view = UIImageView() + private(set) var headingInRadians = 0.0 + private let image: UIImage + + // MARK: - Initializers + + init(){ + image = UIImage(named: "Turtle.png")! + view = UIImageView(image: image) + } + + private init(view: UIImageView, image: UIImage, headingInRadians: Double) { + self.view = view + self.headingInRadians = headingInRadians + self.image = image + } + + // MARK: - Direction + + func increaseHeadingBy(degrees: Double) -> Avatar { + return Avatar(view: view, image: image, headingInRadians: headingInRadians + degrees/180 * M_PI ) + } + + + // MARK: - Position + + func positionTransform(currentPoint: CGPoint) -> CGAffineTransform { + let rotateByRadians = CGAffineTransformMakeRotation(CGFloat(headingInRadians)) + let centerOfTurtleX = currentPoint.x - view.center.x + let centerOfTurtleY = currentPoint.y - view.center.y + let moveTurtle = CGAffineTransformMakeTranslation(centerOfTurtleX, centerOfTurtleY) + let turtleTransform = CGAffineTransformConcat(rotateByRadians, moveTurtle) + return turtleTransform + } + + +} \ No newline at end of file diff --git a/Turtle.playground/Pages/Turtle with Target.xcplaygroundpage/Sources/Secret Turtle Stuff/Constants.swift b/Turtle.playground/Pages/Turtle with Target.xcplaygroundpage/Sources/Secret Turtle Stuff/Constants.swift new file mode 100644 index 0000000..4c7a6e3 --- /dev/null +++ b/Turtle.playground/Pages/Turtle with Target.xcplaygroundpage/Sources/Secret Turtle Stuff/Constants.swift @@ -0,0 +1,27 @@ +import UIKit + +let centerX = 300 +let centerY = 300 +let width = 2 * centerX +let height = 2 * centerY +let terrarium = CGRect(x: 0, y: 0, width: width, height: height) + +let lineWidth: CGFloat = 4.0 + +private let targetOffset = 25 +let targetHorizontalOffset = targetOffset +let targetVerticalOffset = targetOffset +let targetSteps = 11 + +let targetWidth = 2 * targetHorizontalOffset +let targetHeight = 2 * targetVerticalOffset + +let standardForwardDistance = 2 * targetOffset +let rightAngle = 90 + +let environmentColor = UIColor(red: 0.2, + green: 1.0, + blue: 1.0, + alpha: 0.1) +let penColor = UIColor.blackColor() +let victoryColor = UIColor.yellowColor() diff --git a/Turtle.playground/Pages/Turtle with Target.xcplaygroundpage/Sources/Secret Turtle Stuff/Path.swift b/Turtle.playground/Pages/Turtle with Target.xcplaygroundpage/Sources/Secret Turtle Stuff/Path.swift new file mode 100644 index 0000000..3f3d52e --- /dev/null +++ b/Turtle.playground/Pages/Turtle with Target.xcplaygroundpage/Sources/Secret Turtle Stuff/Path.swift @@ -0,0 +1,36 @@ +import UIKit + +struct Path { + var bezierPath = UIBezierPath() + var currentPoint: CGPoint { + return bezierPath.currentPoint + } + + // MARK: - Initializers + + init(startingPoint: CGPoint) { + bezierPath.moveToPoint(startingPoint) + bezierPath.lineWidth = lineWidth + } + + private init(bezierPath: UIBezierPath) { + self.bezierPath = bezierPath + } + + // MARK: - Position + + func moveTo(x x:Double, y: Double) -> Path { + bezierPath.addLineToPoint(CGPoint(x: x, y: y)) + return Path(bezierPath: bezierPath) + } + + func forward(distance: Double, inDirection headingInRadians: Double) -> Path { + let dx = distance * cos(headingInRadians) + let dy = distance * sin(headingInRadians) + let currentX = Double(bezierPath.currentPoint.x) + let currentY = Double(bezierPath.currentPoint.y) + return moveTo(x: currentX + dx, y: currentY + dy) + } + +} + diff --git a/Turtle.playground/Pages/Turtle with Target.xcplaygroundpage/Sources/Secret Turtle Stuff/TargetView.swift b/Turtle.playground/Pages/Turtle with Target.xcplaygroundpage/Sources/Secret Turtle Stuff/TargetView.swift new file mode 100644 index 0000000..717903c --- /dev/null +++ b/Turtle.playground/Pages/Turtle with Target.xcplaygroundpage/Sources/Secret Turtle Stuff/TargetView.swift @@ -0,0 +1,61 @@ +import UIKit +import XCPlayground +import GameKit + +struct Target { + static private let path = (XCPSharedDataDirectoryPath as NSString).stringByAppendingPathComponent("Target.plist") + let targetView = UIImageView(image: UIImage(named: "Target.png")) + let startingMarkerView = UIImageView(image: UIImage(named: "RightArrow.png")) + let targetCoordinateX: Int + let targetCoordinateY: Int + + init() { + (targetCoordinateX, targetCoordinateY) = Target.readFromFile() + positionTargetAndStartingView() + } + private init(targetCoordinateX: Int, targetCoordinateY: Int) { + self.targetCoordinateX = targetCoordinateX + self.targetCoordinateY = targetCoordinateY + positionTargetAndStartingView() + } + + func positionTargetAndStartingView() { + targetView.frame = CGRect(x: targetCoordinateX - targetHorizontalOffset, y: targetCoordinateY - targetVerticalOffset, width: targetWidth, height: targetHeight) + startingMarkerView.frame = CGRect(x: centerX - targetHorizontalOffset, y: centerY - targetVerticalOffset, width: targetWidth, height: targetHeight) + } + + func containsPoint(x: CGFloat, y: CGFloat) -> Bool { + return abs(Int(x) - targetCoordinateX) < targetHorizontalOffset && abs(Int(y) - targetCoordinateY) < targetHorizontalOffset + } + + + + static func readFromFile() -> (Int, Int) { + guard let dictionary = NSDictionary(contentsOfFile: path), x = dictionary["x"] as? NSNumber, y = dictionary["y"] as? NSNumber else { + Target.writeToFile(x: 8 * targetWidth, y: 3 * targetHeight) + return (8 * targetWidth, 3 * targetHeight) + } + return (x.integerValue, y.integerValue) + + } + + static func writeToFile(x x: Int, y: Int) { + let dictionary = ["x" : x, "y" : y] as NSDictionary + dictionary.writeToFile(Target.path, atomically: true) + } + + + func resetTarget() -> Target { + let source = GKARC4RandomSource() + source.dropValuesWithCount(1000) + let distribution = GKShuffledDistribution(lowestValue: 1, highestValue: 11) + let x = distribution.nextInt() * targetWidth + let y = distribution.nextInt() * targetHeight + Target.writeToFile(x: x, y: y) + return Target(targetCoordinateX: x, targetCoordinateY: y) +} + + + + +} diff --git a/Turtle.playground/Pages/Turtle with Target.xcplaygroundpage/Sources/Secret Turtle Stuff/Turtle.swift b/Turtle.playground/Pages/Turtle with Target.xcplaygroundpage/Sources/Secret Turtle Stuff/Turtle.swift new file mode 100644 index 0000000..c25d982 --- /dev/null +++ b/Turtle.playground/Pages/Turtle with Target.xcplaygroundpage/Sources/Secret Turtle Stuff/Turtle.swift @@ -0,0 +1,72 @@ +import UIKit + +public private(set) var turtle = Turtle() + + +public struct Turtle { + + private var currentPath: Path + public let view: TurtleView + private var avatar: Avatar + private let target: Target + + // MARK: - Initializers + + public init() { + let terrariumFrame = CGRect(x: 0, y: 0, width: width, height: height) + avatar = Avatar() + view = TurtleView(frame: terrariumFrame, avatarView: avatar.view) + currentPath = Path(startingPoint: CGPoint(x: centerX , y: centerY)) + target = Target() + view.addPath(currentPath) + view.addSubview(target.targetView) + view.addSubview(target.startingMarkerView) + updateAvatar() + } + private init(currentPath: Path, view: TurtleView, avatar: Avatar, target: Target){ + self.currentPath = currentPath + self.view = view + self.avatar = avatar + self.target = target + updateAvatar() + } + + // MARK: - Position + + func forward(distance: Double) { + let path = currentPath.forward(distance, inDirection: avatar.headingInRadians) + turtle = Turtle(currentPath: path, view: view, avatar: avatar, target: target) + if target.containsPoint(path.currentPoint.x, y: path.currentPoint.y) { + view.backgroundColor = victoryColor + } else { + view.backgroundColor = environmentColor + } + + } + + + // MARK: - Direction + + func increaseHeadingBy(degrees: Double) { + turtle = Turtle(currentPath: currentPath, view: view, avatar: avatar.increaseHeadingBy(degrees), target: target) + + } + + + // MARK: Utility + + private func updateAvatar() { + view.updateAvatarTransform(avatar.positionTransform(currentPath.currentPoint)) + } + func resetTarget() { + turtle = Turtle(currentPath: currentPath, view: view, avatar: avatar, target: target.resetTarget()) + } +} + +extension Turtle: CustomPlaygroundQuickLookable { + public func customPlaygroundQuickLook() -> PlaygroundQuickLook { + + return PlaygroundQuickLook(reflecting: view) + } + +} diff --git a/Turtle.playground/Pages/Turtle with Target.xcplaygroundpage/Sources/Secret Turtle Stuff/TurtleView.swift b/Turtle.playground/Pages/Turtle with Target.xcplaygroundpage/Sources/Secret Turtle Stuff/TurtleView.swift new file mode 100644 index 0000000..e9d26a2 --- /dev/null +++ b/Turtle.playground/Pages/Turtle with Target.xcplaygroundpage/Sources/Secret Turtle Stuff/TurtleView.swift @@ -0,0 +1,34 @@ +import UIKit +import CoreGraphics + + +public class TurtleView: UIView { + private var paths = [Path]() + private var avatarView = UIImageView() + + + // MARK: Initializers + init(frame: CGRect, avatarView: UIImageView) { + super.init(frame: frame) + self.avatarView = avatarView + backgroundColor = environmentColor + addSubview(avatarView) + } + required public init?(coder aDecoder: NSCoder) { + super.init(coder:aDecoder) + } + + // MARK: Draw Methods + override public func drawRect(rect: CGRect) { + for path in paths { + penColor.setStroke() + path.bezierPath.stroke() + } + } + func addPath(path:Path) { + paths.append(path) + } + func updateAvatarTransform(transform: CGAffineTransform) { + avatarView.transform = transform + } +} \ No newline at end of file diff --git a/Turtle.playground/Pages/Turtle with Target.xcplaygroundpage/Sources/TurtleCommands.swift b/Turtle.playground/Pages/Turtle with Target.xcplaygroundpage/Sources/TurtleCommands.swift new file mode 100644 index 0000000..5a9a5e4 --- /dev/null +++ b/Turtle.playground/Pages/Turtle with Target.xcplaygroundpage/Sources/TurtleCommands.swift @@ -0,0 +1,18 @@ +public func forward() { + turtle.forward(Double(standardForwardDistance)) +} + +public func back() { + turtle.forward(Double(-standardForwardDistance)) +} + +public func right() { + turtle.increaseHeadingBy(Double(rightAngle)) +} +public func left() { + turtle.increaseHeadingBy(Double(-rightAngle)) +} + +public func resetTarget() { + turtle.resetTarget() +} \ No newline at end of file diff --git a/Turtle.playground/Pages/Turtle.xcplaygroundpage/Contents.swift b/Turtle.playground/Pages/Turtle.xcplaygroundpage/Contents.swift new file mode 100644 index 0000000..0beb797 --- /dev/null +++ b/Turtle.playground/Pages/Turtle.xcplaygroundpage/Contents.swift @@ -0,0 +1,7 @@ +/*: +### Turtle ([Hint](Turtle%20Hint)) + +[TOC](Contents) | [Previous](@previous) | Next + +--- +*/ diff --git a/Turtle.playground/Pages/Turtle.xcplaygroundpage/Resources/RightArrow.png b/Turtle.playground/Pages/Turtle.xcplaygroundpage/Resources/RightArrow.png new file mode 100644 index 0000000..91688d8 Binary files /dev/null and b/Turtle.playground/Pages/Turtle.xcplaygroundpage/Resources/RightArrow.png differ diff --git a/Turtle.playground/Pages/Turtle.xcplaygroundpage/Resources/Target.png b/Turtle.playground/Pages/Turtle.xcplaygroundpage/Resources/Target.png new file mode 100644 index 0000000..cb3c7c2 Binary files /dev/null and b/Turtle.playground/Pages/Turtle.xcplaygroundpage/Resources/Target.png differ diff --git a/Turtle.playground/Pages/Turtle.xcplaygroundpage/Resources/Turtle.png b/Turtle.playground/Pages/Turtle.xcplaygroundpage/Resources/Turtle.png new file mode 100644 index 0000000..d78537f Binary files /dev/null and b/Turtle.playground/Pages/Turtle.xcplaygroundpage/Resources/Turtle.png differ diff --git a/Turtle.playground/Pages/Turtle.xcplaygroundpage/Sources/Secret Turtle Stuff/Avatar.swift b/Turtle.playground/Pages/Turtle.xcplaygroundpage/Sources/Secret Turtle Stuff/Avatar.swift new file mode 100644 index 0000000..4cb4c18 --- /dev/null +++ b/Turtle.playground/Pages/Turtle.xcplaygroundpage/Sources/Secret Turtle Stuff/Avatar.swift @@ -0,0 +1,61 @@ +import UIKit + +struct Avatar { + private(set) var view = UIImageView() + private(set) var headingInRadians = 0.0 + private let image: UIImage + + // MARK: - Initializers + + init(){ + image = UIImage(named: "Turtle.png")! + view = UIImageView(image: colorAvatar(initialPenColor)) + } + + private init(view: UIImageView, image: UIImage, headingInRadians: Double) { + self.view = view + self.headingInRadians = headingInRadians + self.image = image + } + + // MARK: - Direction + + func setHeadingTo(degrees: Double) -> Avatar { + return Avatar(view: view, image: image, headingInRadians: degrees/180 * M_PI) + } + + func increaseHeadingBy(degrees: Double) -> Avatar { + return Avatar(view: view, image: image, headingInRadians: headingInRadians + degrees/180 * M_PI ) + } + + + // MARK: - Position + + func positionTransform(currentPoint: CGPoint) -> CGAffineTransform { + let rotateByRadians = CGAffineTransformMakeRotation(CGFloat(headingInRadians)) + let centerOfTurtleX = currentPoint.x - view.center.x + let centerOfTurtleY = currentPoint.y - view.center.y + let moveTurtle = CGAffineTransformMakeTranslation(centerOfTurtleX, centerOfTurtleY) + let turtleTransform = CGAffineTransformConcat(rotateByRadians, moveTurtle) + return turtleTransform + } + + // MARK: - Color + + func penColor(penColor: PenColor) -> Avatar { + view.image = colorAvatar(penColor) + return Avatar(view: view, image: image, headingInRadians: headingInRadians) + } + + private func colorAvatar(penColor: PenColor) -> UIImage { + let angle = penColor.hue * M_PI * 2.0 + guard let inputImage = CIImage(image: image), + let hueAdjuster = CIFilter(name: "CIHueAdjust", withInputParameters: [kCIInputImageKey : inputImage , + kCIInputAngleKey : NSNumber(double: angle)]) else { + return image + } + return UIImage(CIImage: hueAdjuster.outputImage!) + } + + +} \ No newline at end of file diff --git a/Turtle.playground/Pages/Turtle.xcplaygroundpage/Sources/Secret Turtle Stuff/Constants.swift b/Turtle.playground/Pages/Turtle.xcplaygroundpage/Sources/Secret Turtle Stuff/Constants.swift new file mode 100644 index 0000000..2686f9d --- /dev/null +++ b/Turtle.playground/Pages/Turtle.xcplaygroundpage/Sources/Secret Turtle Stuff/Constants.swift @@ -0,0 +1,23 @@ +import UIKit + +let centerX = 300 +let centerY = 300 +let width = 2 * centerX +let height = 2 * centerY +let terrarium = CGRect(x: 0, y: 0, width: width, height: height) + +let lineWidth: CGFloat = 4.0 + +private let targetOffset = 25 +let targetHorizontalOffset = targetOffset +let targetVerticalOffset = targetOffset +let targetSteps = 11 + +let targetWidth = 2 * targetHorizontalOffset +let targetHeight = 2 * targetVerticalOffset + +let standardForwardDistance = Double(2 * targetOffset) +let rightAngle = 90.0 + +let environmentColor = UIColor.blackColor() +let initialPenColor = PenColor.Green diff --git a/Turtle.playground/Pages/Turtle.xcplaygroundpage/Sources/Secret Turtle Stuff/Path.swift b/Turtle.playground/Pages/Turtle.xcplaygroundpage/Sources/Secret Turtle Stuff/Path.swift new file mode 100644 index 0000000..33ce0a9 --- /dev/null +++ b/Turtle.playground/Pages/Turtle.xcplaygroundpage/Sources/Secret Turtle Stuff/Path.swift @@ -0,0 +1,52 @@ +import UIKit + +struct Path { + var bezierPath = UIBezierPath() + var currentPoint: CGPoint { + return bezierPath.currentPoint + } + let penColor: PenColor + let isPenDown: Bool + + // MARK: - Initializers + + init(startingPoint: CGPoint, penColor: PenColor = initialPenColor) { + bezierPath.moveToPoint(startingPoint) + bezierPath.lineWidth = lineWidth + self.penColor = penColor + self.isPenDown = true + } + + private init(bezierPath: UIBezierPath, penColor: PenColor, isPenDown: Bool) { + self.bezierPath = bezierPath + self.penColor = penColor + self.isPenDown = isPenDown + } + + // MARK: - Position + + func moveTo(x x:Double, y: Double) -> Path { + if isPenDown { + bezierPath.addLineToPoint(CGPoint(x: x, y: y)) + } else { + bezierPath.moveToPoint(CGPoint(x: x, y: y)) + } + return Path(bezierPath: bezierPath, penColor: penColor, isPenDown: isPenDown) + } + + func forward(distance: Double, inDirection headingInRadians: Double) -> Path { + let dx = distance * cos(headingInRadians) + let dy = distance * sin(headingInRadians) + let currentX = Double(bezierPath.currentPoint.x) + let currentY = Double(bezierPath.currentPoint.y) + return moveTo(x: currentX + dx, y: currentY + dy) + } + + // MARK: Visibility + + func penDown(isPenDown: Bool) -> Path { + return Path(bezierPath: bezierPath, penColor: penColor, isPenDown: isPenDown) + } + +} + diff --git a/Turtle.playground/Pages/Turtle.xcplaygroundpage/Sources/Secret Turtle Stuff/PenColor.swift b/Turtle.playground/Pages/Turtle.xcplaygroundpage/Sources/Secret Turtle Stuff/PenColor.swift new file mode 100644 index 0000000..22daeb2 --- /dev/null +++ b/Turtle.playground/Pages/Turtle.xcplaygroundpage/Sources/Secret Turtle Stuff/PenColor.swift @@ -0,0 +1,25 @@ +import UIKit + +public enum PenColor: Int { + case Red + case Orange + case Yellow + case PeaGreen, Green, BlueGreen + case Cyan, Cerullian, Blue + case Purple, Magenta, Pink + + + var color: UIColor { + return UIColor(hue: CGFloat(hue), saturation: 1, brightness: 1, alpha: 1) + } + + func next() -> PenColor { + let numberOfNextColor = (rawValue + 7) % PenColor.Pink.rawValue + return PenColor(rawValue: numberOfNextColor)! + } + + var hue: Double { + return Double(rawValue)/12.0 + } +} + diff --git a/Turtle.playground/Pages/Turtle.xcplaygroundpage/Sources/Secret Turtle Stuff/Turtle.swift b/Turtle.playground/Pages/Turtle.xcplaygroundpage/Sources/Secret Turtle Stuff/Turtle.swift new file mode 100644 index 0000000..2a75a9d --- /dev/null +++ b/Turtle.playground/Pages/Turtle.xcplaygroundpage/Sources/Secret Turtle Stuff/Turtle.swift @@ -0,0 +1,88 @@ +import UIKit + +public private(set) var turtle = Turtle() + + +public struct Turtle { + + private var currentPath: Path + public let view: TurtleView + private var avatar: Avatar + + // MARK: - Initializers + + public init() { + let terrariumFrame = CGRect(x: 0, y: 0, width: width, height: height) + avatar = Avatar() + view = TurtleView(frame: terrariumFrame, avatarView: avatar.view) + currentPath = Path(startingPoint: CGPoint(x: centerX , y: centerY)) + view.addPath(currentPath) + updateAvatar() + } + + private init(currentPath: Path, view: TurtleView, avatar: Avatar){ + self.currentPath = currentPath + self.view = view + self.avatar = avatar + updateAvatar() + } + + // MARK: - Position + + func forward(distance: Double) { + let path = currentPath.forward(distance, inDirection: avatar.headingInRadians) + turtle = Turtle(currentPath: path, view: view, avatar: avatar) + } + + func moveTo(x x: Double, y: Double) { + let path = currentPath.moveTo(x: x, y: y) + turtle = Turtle(currentPath: path, view: view, avatar: avatar) + } + + // MARK: - Colors + + func penColor(penColor: PenColor) { + let path = Path(startingPoint:currentPath.currentPoint, penColor: penColor ) + view.addPath(path) + turtle = Turtle(currentPath: path, view: view, avatar: avatar.penColor(penColor)) + + } + func nextColor() { + penColor(currentPath.penColor.next()) + } + + // MARK: - Direction + + func increaseHeadingBy(degrees: Double) { + turtle = Turtle(currentPath: currentPath, view: view, avatar: avatar.increaseHeadingBy(degrees)) + + } + func setHeadingTo(degrees: Double) { + turtle = Turtle(currentPath: currentPath, view: view, avatar: avatar.setHeadingTo(degrees)) + } + + // MARK: - Appearance + func hideTurtle(isHidden: Bool = true) { + view.hideTurtle(isHidden) + } + + func penDown(isDown: Bool = true) { + turtle = Turtle(currentPath: currentPath.penDown(isDown), view: view, avatar: avatar) + } + + + + // MARK: Utility + + private func updateAvatar() { + view.updateAvatarTransform(avatar.positionTransform(currentPath.currentPoint)) + } +} + +extension Turtle: CustomPlaygroundQuickLookable { + public func customPlaygroundQuickLook() -> PlaygroundQuickLook { + + return PlaygroundQuickLook(reflecting: view) + } + +} diff --git a/Turtle.playground/Pages/Turtle.xcplaygroundpage/Sources/Secret Turtle Stuff/TurtleView.swift b/Turtle.playground/Pages/Turtle.xcplaygroundpage/Sources/Secret Turtle Stuff/TurtleView.swift new file mode 100644 index 0000000..8617862 --- /dev/null +++ b/Turtle.playground/Pages/Turtle.xcplaygroundpage/Sources/Secret Turtle Stuff/TurtleView.swift @@ -0,0 +1,40 @@ +import UIKit +import CoreGraphics + + +public class TurtleView: UIView { + private var paths = [Path]() + private var avatarView = UIImageView() + + + // MARK: Initializers + init(frame: CGRect, avatarView: UIImageView) { + super.init(frame: frame) + self.avatarView = avatarView + backgroundColor = environmentColor + addSubview(avatarView) + } + required public init?(coder aDecoder: NSCoder) { + super.init(coder:aDecoder) + } + + // MARK: Draw Methods + override public func drawRect(rect: CGRect) { + for path in paths { + path.penColor.color.setStroke() + path.bezierPath.stroke() + } + } + func addPath(path:Path) { + paths.append(path) + } + func updateAvatarTransform(transform: CGAffineTransform) { + avatarView.transform = transform + } + + // MARK: Show or hide turtle + + func hideTurtle(isHidden: Bool = true) { + avatarView.hidden = isHidden + } +} \ No newline at end of file diff --git a/Turtle.playground/Pages/Turtle.xcplaygroundpage/Sources/TurtleCommands.swift b/Turtle.playground/Pages/Turtle.xcplaygroundpage/Sources/TurtleCommands.swift new file mode 100644 index 0000000..4807bb9 --- /dev/null +++ b/Turtle.playground/Pages/Turtle.xcplaygroundpage/Sources/TurtleCommands.swift @@ -0,0 +1,50 @@ +public func forward(distance: Double = standardForwardDistance) { + turtle.forward(distance) +} + +public func back(distance: Double = standardForwardDistance) { + forward(-distance) +} + +public func moveTo(x x: Double, y: Double) { + turtle.moveTo(x: x, y: y) +} + +public func right(angle: Double = rightAngle) { + turtle.increaseHeadingBy(angle) +} +public func left(angle: Double = rightAngle) { + right(angle) +} +public func setHeadingTo(degrees: Double) { + turtle.setHeadingTo(degrees) +} +public func home() { + penUp() + moveTo(x: Double(centerX), y: Double(centerY)) + setHeadingTo(0) + penDown() +} + +public func penColor(penColor:PenColor){ + turtle.penColor(penColor) +} + +public func nextColor() { + turtle.nextColor() +} + +public func penDown() { + turtle.penDown() +} +public func penUp() { + turtle.penDown(false) +} + + +public func hide() { + turtle.hideTurtle() +} +public func show() { + turtle.hideTurtle(false) +} diff --git a/Turtle.playground/contents.xcplayground b/Turtle.playground/contents.xcplayground new file mode 100644 index 0000000..17e582d --- /dev/null +++ b/Turtle.playground/contents.xcplayground @@ -0,0 +1,2 @@ + + \ No newline at end of file