Last active
September 1, 2016 07:23
-
-
Save pofat/27878e68d3da276e0078e5377e66ec37 to your computer and use it in GitHub Desktop.
Battleship in OOP and FP
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
typealias Distance = Double | |
/// A struct to represent real position of the ship | |
struct Position { | |
var x: Double | |
var y: Double | |
} | |
extension Position { | |
/// Calculate if this position lies in the given range | |
func inRange(range: Distance) -> Bool { | |
return sqrt(x*x + y*y) <= range | |
} | |
} | |
/// The struct to represent the ship | |
struct Ship { | |
var position: Position | |
var firingRange: Distance | |
var unsafeRange: Distance | |
} | |
/* check if target locates in the firing range */ | |
extension Ship { | |
/// If the target locates in the firing range | |
func canEngageShip(target: Ship) -> Bool { | |
let dx = target.position.x - position.x | |
let dy = target.position.y - position.y | |
let targetDistance = sqrt(dx * dx + dy * dy) | |
return targetDistance <= firingRange | |
} | |
} | |
/* Also assure the target is not too close */ | |
extension Ship { | |
/// If traget locates within firingRange but outside unsafeRange | |
func canSafelyEngageShip(target: Ship) -> Bool { | |
let dx = target.position.x - position.x | |
let dy = target.position.y - position.y | |
let targetDistance = sqrt(dx * dx + dy * dy) | |
return targetDistance <= firingRange && targetDistance > unsafeRange | |
} | |
} | |
/* target can not stay within the unsafeRange of friend ship while firing */ | |
extension Ship { | |
func canSafelyEngageShip1(target: Ship, freindly: Ship) -> Bool { | |
let dx = target.position.x - position.x | |
let dy = target.position.y - position.y | |
let targetDistance = sqrt(dx * dx + dy * dy) | |
let friendlyDx = friendly.position.x - target.position.x | |
let friendlyDy = friendly.position.y - target.position.y | |
let friendlyDistance = sqrt(friendlyDx * friendlyDx + | |
friendlyDy * friendlyDy) | |
return targetDistance <= firingRange | |
&& targetDistance > unsafeRange | |
&& (friendlyDistance > unsafeRange) | |
} | |
} | |
/* -------------------------------- | |
* Rewrite in FP | |
* -------------------------------- | |
* | |
* We need a function to handle if a position locates in a range, such as: | |
* func pointInRange(point: Position) -> Bool { //... } | |
* | |
* So we give this function a type | |
*/ | |
typealias Region = Position -> Bool | |
extension Position { | |
/// minus two points | |
func minus(p: Position) -> Position { | |
return Position(x: x - p.x, y: y - p.y) | |
} | |
/// Length from the origin | |
var length: Double { | |
return sqrt(x * x + y * y) | |
} | |
} | |
/// A circle whose center locates at origin | |
func circle(radius: Distance) -> Region { | |
return { point in point.length <= radius } | |
} | |
/// A ciricl which can be assigned its center other than origin | |
func circle2(radius: Distance, center: Position) -> Region { | |
return { point in point.minus(center).length <= radius } | |
} | |
/// A method to shift the region, need to send a point to check if it locates in the NEW region | |
func shift(region: Region, offset: Position) -> Region { | |
return { point in region(point.minus(offset)) } | |
} | |
/* to replace circle2 */ | |
shift(circle(10), offset: Position(5,5)) | |
/* more operation to region */ | |
func invert(region: Region) -> Region { | |
return { point in !region(point) } | |
} | |
/// A&B | |
func intersection(region1: Region, _ region2: Region) -> Region { | |
return { point in region1(point) && region2(point) } | |
} | |
/// A|B | |
func union(region1: Region, _ region2: Region) -> Region { | |
return { point in region1(point) || region2(point) } | |
} | |
/// A - A&B | |
func difference(region: Region, minus: Region) -> Region { | |
return intersection(region, invert(minus)) | |
} | |
// Rewrite in functions | |
extension Ship { | |
func canSafelyEngageShipRewrite(target: Ship, friendly: Ship) -> Bool { | |
// assemble functions to determine engaging range (center is origin) | |
let rangeRegion = difference(circle(firingRange), | |
minus: circle(unsafeRange)) | |
// move center to where the ship is | |
let firingRegion = shift(rangeRegion, offset: position) | |
// assemble functions to determine real unsafe range | |
let friendlyRegion = shift(circle(unsafeRange), | |
offset: friendly.position) | |
// assemble function for final firing region | |
let resultRegion = difference(firingRegion, minus: friendlyRegion) | |
// send in argument | |
return resultRegion(target.position) | |
} | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment