Skip to content

Instantly share code, notes, and snippets.

@blakemerryman
Created December 22, 2014 19:40

Revisions

  1. blakemerryman created this gist Dec 22, 2014.
    195 changes: 195 additions & 0 deletions gistfile1.txt
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,195 @@
    #!/usr/bin/env xcrun swift

    /*
    /r/DailyProgrammer Challenge # 193
    Reddit - http://www.reddit.com/r/dailyprogrammer/
    Blake Merryman
    Github - https://github.com/blakemerryman
    Challenge Description:
    An international shipping company is trying to figure out how to manufacture various types of containers. Given a volume they want to figure out the dimensions of various shapes that would all hold the same volume.
    Input:
    * A volume in cubic meters.
    Output:
    * Dimensions of containers of various types that would hold the volume.
    * The following containers are possible.
    * Cube
    * Ball (Sphere)
    * Cylinder
    * Cone
    Ex:
    Input:
    > 27.0
    Output:
    > Cube: 3.00m width, 3.00m high, 3.00m tall
    Cylinder: 3.00m tall, Diameter of 3.38m
    Sphere: 1.86m Radius
    Cone: 9.00m tall, 1.69m Radius
    Notes:
    * Input can be an integer or double value
    * To run,
    1. Make executable (chmod +x filename.swift)
    2. Run by entering the following into the console:
    > ./filename.swift ###
    or
    > ./filename.swift ###.##
    */

    import Cocoa


    // MARK: - Handle User Input

    var volume = 0.0

    // Grab input from console
    for argument in Process.arguments {

    let argumentAsDouble = (argument as NSString).doubleValue

    if argumentAsDouble > 0.0 {
    volume = argumentAsDouble
    }
    }

    // MARK: - Important Constants & Enums

    let kDimensionUnits = "m"
    let kDimensionHeight = "height"
    let kDimensionWidth = "width"
    let kDimensionDepth = "depth"
    let kDimensionRadius = "radius"

    enum ContainerShape: String {
    case Cube = "Cube"
    case Sphere = "Sphere"
    case Cylinder = "Cylinder"
    case Cone = "Cone"
    }


    // MARK: - NumberFormatter

    var numberFormatter = NSNumberFormatter()

    numberFormatter.maximumSignificantDigits = {
    var numberOfSigDigs = 0
    for character in volume.description {
    if character != "." {
    numberOfSigDigs++
    }
    }
    return numberOfSigDigs
    }()

    // MARK: - Utility Functions

    /// Computes the height, width, & depth of a cube for a given volume.
    func computeDimensionsForCubeWithVolume(volume: Double) -> [String:Double] {

    let aSide = cbrt(volume)

    return [kDimensionHeight:aSide, kDimensionWidth: aSide, kDimensionDepth: aSide]
    }

    /// Computes the radius of a sphere for a given volume.
    func computeDimensionsForSphereWithVolume(volume: Double) -> [String:Double] {

    let radius = cbrt( ( 3.0 * volume ) / ( 4.0 * M_PI ) )

    return [kDimensionRadius:radius]
    }

    /// Computes the height & radius of a cylinder with minimum surface area for given volume.
    func computeDimensionsForCylinderWithVolume(volume: Double) -> [String:Double] {

    /*
    Note on calculations:

    We know the desired volume of the cylinder but not the desired dimensions.
    This is an equation with two unknowns and in the Real numbers could have many
    possible solutions. To narrow it down to one, we are going to use a little
    calculus to minimize the surface area and thus give us the appropriate
    radius & height for the given volume.

    User copper.hat gives a great explanation behind getting the correct formulae
    for the radius and height ( http://math.stackexchange.com/a/584770 ).
    */

    let radius = cbrt(volume / (2 * M_PI))
    let height = cbrt((4 * volume) / M_PI)

    return [kDimensionRadius:radius,kDimensionHeight:height]
    }

    /// Computes the height & radius of a cone with a slant angle of 45º for given volume.
    func computeDimensionsForConeWithVolume(volume: Double) -> [String:Double] {

    /*
    Note on calculations:

    We know the desired volume of the cone but not the desired dimensions.
    This is an equation with two unknowns and in the Real numbers could have many
    possible solutions. To narrow it down to one, we are going to assume that
    height and radius are equal, giving us a slant angle of 45º.

    We could make any number of assumptions (desired slant angle, maximum height,
    maximum radius, etc) but this one was chosen for simplicity.

    V = ( h * pi * r^2 ) / 3 ... but h = r so
    = ( pi * r^3 ) / 3 ... and solving for r gives us...
    */

    let radius = cbrt((3 * volume) / M_PI)

    return [kDimensionRadius:radius,kDimensionHeight:radius]
    }

    // Given a set of dimensions & shape, properly formats the string for output.
    func formatDimensions(dimensions: [String:Double], forShape shape: ContainerShape) -> String {

    switch shape {

    case .Cube:
    let height = numberFormatter.stringFromNumber(dimensions[kDimensionHeight]!)!
    let width = numberFormatter.stringFromNumber(dimensions[kDimensionWidth]!)!
    let depth = numberFormatter.stringFromNumber(dimensions[kDimensionDepth]!)!
    return "\(shape.rawValue): \(height) \(kDimensionUnits) \(kDimensionHeight), \(width) \(kDimensionUnits) \(kDimensionWidth), \(depth) \(kDimensionUnits) \(kDimensionDepth)"

    case .Cone, .Cylinder:
    let radius = numberFormatter.stringFromNumber(dimensions[kDimensionRadius]!)!
    let height = numberFormatter.stringFromNumber(dimensions[kDimensionHeight]!)!
    return "\(shape.rawValue): \(radius) \(kDimensionUnits) \(kDimensionRadius),\(height) \(kDimensionUnits) \(kDimensionHeight)"

    case .Sphere:
    let radius = numberFormatter.stringFromNumber(dimensions[kDimensionRadius]!)!
    return "\(shape.rawValue): \(radius) \(kDimensionUnits) \(kDimensionRadius)"
    }
    }

    // MARK: - Primary Function

    /// Function computes possible dimensions for the passed in shape & volume. Computed values are returned in a dictionary.
    func computeDimensions(forShape shape: ContainerShape, withVolume volume: Double) -> String {
    switch shape {
    case .Cube:
    return formatDimensions(computeDimensionsForCubeWithVolume(volume), forShape: .Cube)
    case .Cone:
    return formatDimensions(computeDimensionsForConeWithVolume(volume), forShape: .Cone)
    case .Cylinder:
    return formatDimensions(computeDimensionsForCylinderWithVolume(volume), forShape: .Cylinder)
    case .Sphere:
    return formatDimensions(computeDimensionsForSphereWithVolume(volume), forShape: .Sphere)
    }
    }


    // --------------------------------------------------
    // MARK: - Comput & Output to User

    println("\n\nContainer Dimensions for a given volume of \(volume) \(kDimensionUnits)^3")
    println("----------------------------------------------------------")
    println("\(computeDimensions(forShape: .Cube, withVolume: volume))")
    println("\(computeDimensions(forShape: .Cone, withVolume: volume))")
    println("\(computeDimensions(forShape: .Cylinder, withVolume: volume))")
    println("\(computeDimensions(forShape: .Sphere, withVolume: volume))")
    println("----------------------------------------------------------\n\n")