 # Silver and Golden Challenges Solutions

After checking the existing solutions at the forum share mine here as they are very different.

Post here only the code relevant to the solutions.

***** Silver Challenge Solution *****

struct Line {

``````// Sine of the angle as a CGFloat accepted by UIColor initializer
var angleSin: CGFloat {
let x = Double(abs(Int32(end.x - begin.x)))
let y = Double(abs(Int32(end.y - begin.y)))
let h = sqrt(pow(x, 2) + pow(y, 2))
return CGFloat(y / h)
}
``````

}

class DrawView: UIView {

``````override func draw(_ rect: CGRect) {
...
for (_, line) in currentLines {
currentLineColor = UIColor(hue: line.angleSin, saturation: 1, brightness: 1, alpha: 1)
...
}
}
``````

}

***** Golden Challenge Solution *****

struct Circle {

``````var begin = CGPoint.zero
var end = CGPoint.zero

var ovalRectangle: CGRect { // Cicle is boring, oval is more facinating
let x = CGFloat(Int32(end.x - begin.x))
let y = CGFloat(Int32(end.y - begin.y))
let size = CGSize(width: x, height: y)
return CGRect(origin: begin, size: size)
}

var circleRectangle: CGRect {
let x = CGFloat(abs(Int32(end.x - begin.x)))
let y = CGFloat(abs(Int32(end.y - begin.y)))
let side = min(x, y)
let size = CGSize(width: side, height: side)
let center = CGPoint(x: (begin.x + end.x) / 2, y: (begin.y + end.y) / 2)
let origin = CGPoint(x: center.x - side / 2, y: center.y - side / 2)
return CGRect(origin: origin, size: size)
}

//Using this assignment function prevents losing built-in memberwise initialiser plus adds defencing
mutating func setLocation(_ locations: [CGPoint]) {
if locations.count != 2 {
return
}
begin = locations
end = locations
}
``````

}

class DrawView: UIView {

``````...

var circleTouches = [NSValue: CGPoint]()
var currentCircle: Circle?
var finishedCircles = [Circle]()

...

private func strokeCircle(_ circle: Circle) {
let path = UIBezierPath(ovalIn: circle.circleRectangle)
path.lineWidth = lineThickness
path.stroke()
}

override func draw(_ rect: CGRect) {
finishedLineColor.setStroke()

...

for circle in finishedCircles {
strokeCircle(circle)
}

currentLineColor.setStroke()

if let circle = currentCircle {
strokeCircle(circle)
}

...
}

//MARK: - Handling touches
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
if touches.count == 2 {
currentCircle = Circle()
updateCirle(fromTouches: touches)
} else {
...
}
setNeedsDisplay()
}

override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
if touches.count == 2, let _ = currentCircle {
updateCirle(fromTouches: touches)
} else {
...
}
setNeedsDisplay()
}

override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
if touches.count == 2, let _ = currentCircle {
updateCirle(fromTouches: touches)
finishedCircles.append(currentCircle!)
currentCircle = nil
circleTouches.removeAll()
} else {
...
}
setNeedsDisplay()
}

override func touchesCancelled(_ touches: Set<UITouch>, with event: UIEvent?) {
...
circleTouches.removeAll()
currentCircle = nil
setNeedsDisplay()
}

private func updateCirle(fromTouches touches: Set<UITouch>) {
for touch in touches {
let location = touch.location(in: self)
let key = NSValue(nonretainedObject: touch)
circleTouches[key] = location
}
let locations = Array(circleTouches.values)
currentCircle!.setLocation(locations)
}
``````

}