Skip to content

Instantly share code, notes, and snippets.

@pofat
Last active September 1, 2016 07:23
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save pofat/27878e68d3da276e0078e5377e66ec37 to your computer and use it in GitHub Desktop.
Save pofat/27878e68d3da276e0078e5377e66ec37 to your computer and use it in GitHub Desktop.
Battleship in OOP and FP
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