# Regions - Simplified Inheritance Approach

``````import Darwin
struct Position { let x, y: Float }
typealias Distance = Float

protocol Containsable
{
func contains(position: Position) -> Bool
}

class Region: Containsable
{
func contains(position: Position) -> Bool
{
assert(false, "subclass MUST override")
}
}

class Circle: Region
{

// have to manually write inits, because it's a class (boo!)
{
}

// have to mark as override (nice!)
override func contains(position: Position) -> Bool
{
}
}

class ComposedRegion: Region
{
let containsRule: Position -> Bool  ///< holds the complex logic as a function

init(containsRule: Position -> Bool)
{
self.containsRule = containsRule
}

override func contains(position: Position) -> Bool
{
return containsRule(position)
}
}

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Instead of using RegionTransformer, then making the convenience functions, just do it all directly in Region
// There might be a down-side to this, but I'm not sure what it is…

extension Region
{
func shift(by offset: Position) -> Region
{
return ComposedRegion(containsRule: {
point in
let shiftedPoint = Position(x: point.x - offset.x, y: point.y - offset.y)
return self.contains(shiftedPoint)
})
}

func invert() -> Region
{
return ComposedRegion(containsRule: { point in !self.contains(point) })
}

func intersection(with other: Region) -> Region
{
return ComposedRegion(containsRule: { point in
self.contains(point) && other.contains(point)
})
}

func union(with other: Region) -> Region
{
return ComposedRegion(containsRule: { point in
self.contains(point) || other.contains(point)
})
}

func difference(minus region: Region) -> Region
{
return self.intersection(with: region.invert())
}
}

// simple example
let shiftedCircle = circle.shift(by: Position(x: 10, y: 12))
shiftedCircle.contains(Position(x: 11, y: 13))

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Now, the complex example

let ownPosition = Position(x: 10, y: 12)
let weaponRange = Circle(radius: 5.0)   // <-- just make this a struct
let safeDistance = Circle(radius: 1.0)   // <-- and this
let friendlyRegion = safeDistance.shift(by: Position(x: 12, y: 9))

let shouldFireAtTarget = weaponRange
.difference(minus: safeDistance)
.shift(by: ownPosition)
.difference(minus: friendlyRegion)

// Test it
shouldFireAtTarget.contains(Position(x: 0, y: 0))  // too far away
shouldFireAtTarget.contains(Position(x: 9, y: 15))  // hit!
shouldFireAtTarget.contains(Position(x: 10.5, y: 12))  // too close to self
shouldFireAtTarget.contains(Position(x: 12.25, y: 9.25))  // too close to friendly
``````