Created
February 2, 2015 04:18
-
-
Save all-user/7886df0b9563fe70f5c3 to your computer and use it in GitHub Desktop.
CodeIQ 「中学入試から:概数と計算」提出コード
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
// | |
// main.swift | |
// | |
import Foundation | |
/** | |
* ~/Documents(/Users/ユーザ名/Documents)を取得するコードです。 | |
* ここにdata.txtを配置する方法しか読み込む方法が分からなかったので、すいません。。。 | |
*/ | |
let dirs = NSSearchPathForDirectoriesInDomains( | |
NSSearchPathDirectory.DocumentDirectory, | |
NSSearchPathDomainMask.AllDomainsMask, true) as? [String] | |
if let _path = dirs?[0] { // "Users/.../Documents" | |
if let data = String( | |
contentsOfFile: _path + "/data.utf8.txt", | |
encoding: NSUTF8StringEncoding, error: nil) | |
{ | |
let TESTCASE_SIZE = 50 | |
let onlyTestCase = false | |
var cnt = 0 | |
var failedIDs = [String]() | |
let start = NSDate.timeIntervalSinceReferenceDate() // 開始時間を記録 | |
data.enumerateLines{ line, stop in | |
cnt++; | |
if onlyTestCase { | |
if cnt > TESTCASE_SIZE { return } // テスト用データのみを実行 | |
} else { | |
if cnt <= TESTCASE_SIZE { return } // テスト用データを除外 | |
} | |
let data = RoundingRangeDate(raw: line) | |
let b = data.checkData() | |
if !b { failedIDs.append(data.id) } | |
} | |
println(join(",", failedIDs)) | |
println(NSDate.timeIntervalSinceReferenceDate() - start) // 経過時間を出力 | |
} | |
} | |
// | |
// RoundingRangeDate.swift | |
// | |
func processToOffset(s:String) -> Double? { | |
switch s { | |
case "四捨五入": return 0.5 | |
case "切り上げ": return 0.0 | |
case "切り捨て": return 1.0 | |
default: | |
println("Exception in processToOffset : s => \(s)") | |
return nil | |
} | |
} | |
func shiftDigitRight(var base:Double, var n:Int) -> Double { | |
while n-- != 0 { | |
base /= 10 | |
} | |
return base | |
} | |
// DoubleをStringに変換してから小数点をずらして再びDoubleにパース | |
func shiftDigitLeft(base:Double, var move:Int) -> (n:Double, r:Bool) { | |
var sep = base.description.componentsSeparatedByString(".") | |
let insert = sep[0].utf16Count + move | |
var newStr = "" | |
var rStr = "" | |
var i = 0 | |
var r = false | |
if sep[1].utf16Count <= move { | |
let zeroArr = [String](count: move - sep[1].utf16Count, repeatedValue: "0") | |
sep.append(join("", zeroArr)) | |
} | |
for c in join("", sep) { | |
if i >= insert { | |
if i == insert { newStr += "." } | |
rStr += String(c) | |
} else { | |
newStr += String(c) | |
} | |
i++ | |
} | |
if rStr.toInt() > 0 { | |
r = true | |
newStr += "5" | |
} | |
return (newStr.doubleValue(), r) | |
} | |
struct RoundingRangeDate { | |
let id:String | |
let scale:Double | |
let targetSize:Double | |
let resultRange:[Double]? | |
let offset1:Double | |
let offset2:Double | |
let pointPosition1:Int | |
let pointPosition2:Int | |
init (raw:String) { // data.txtの各行からインスタンスを生成 | |
var _raw = split(raw){ $0 == "\t" } | |
id = _raw[0] | |
pointPosition1 = _raw[1].toInt()! | |
offset1 = processToOffset(_raw[2])! | |
scale = _raw[3].doubleValue() | |
pointPosition2 = _raw[4].toInt()! | |
offset2 = processToOffset(_raw[5])! | |
targetSize = _raw[6].doubleValue() | |
resultRange = { (line:String) -> [Double]? in | |
if line == "なし" { return nil } | |
var separator = (line.rangeOfString("以上") != nil) ? "以上" : "より大きく" | |
var arr = line.componentsSeparatedByString(separator) | |
let start = arr[0].doubleValue() | |
separator = (arr[1].rangeOfString("未満") != nil) ? "未満" : "以下" | |
arr = arr[1].componentsSeparatedByString(separator) | |
let end = arr[0].doubleValue() | |
return [start, end] | |
}(_raw[7]) | |
} | |
func checkData() -> Bool { | |
let remainderCheck = shiftDigitLeft(self.targetSize, self.pointPosition2 - 1) | |
if remainderCheck.r { // 処理を行う桁に余剰が有れば、"なし"になるので終了 | |
return self.resultRange == nil | |
} | |
var currentDigit = shiftDigitRight(1, self.pointPosition2 - 1) | |
let high = self.targetSize + self.offset2 * currentDigit | |
let low = high - currentDigit | |
var range = [low, high] | |
var i = 0 | |
range = range.map{ (var n:Double) -> Double in | |
n /= self.scale | |
let (_n, r) = shiftDigitLeft(n, self.pointPosition1) | |
return _n | |
} | |
var (n1, n2) = (range[0], range[1]) | |
var r:Double | |
switch (self.offset1, self.offset2) { // 一度目と二度目の処理の組み合わせにより処理を分岐 | |
case (0.5, 0.0) : // 四捨五入 -> 切り上げ | |
r = n1 % 10 | |
range[0] = { () -> Double in | |
var _n1 = n1 - r | |
while !(n1 < _n1) { | |
_n1 += 10 | |
} | |
return _n1 - 5 | |
}() | |
r = n2 % 10 | |
range[1] = { () -> Double in | |
var _n2 = n2 - r | |
while !(_n2 <= n2) { | |
_n2 -= 10 | |
} | |
return _n2 + 5 | |
}() | |
case (1.0, 0.0): // 切り下げ -> 切り上げ | |
r = n1 % 10 | |
range[0] = { () -> Double in | |
var _n1 = n1 - r | |
while !(n1 < _n1) { | |
_n1 += 10 | |
} | |
return _n1 | |
}() | |
r = n2 % 10 | |
range[1] = { () -> Double in | |
var _n2 = n2 - r | |
while !(_n2 <= n2) { | |
_n2 -= 10 | |
} | |
return _n2 + 10 | |
}() | |
case (0.5, _): // 四捨五入 -> 四捨五入または切り下げ | |
r = n1 % 10 | |
range[0] = { () -> Double in | |
var _n1 = n1 - r | |
while !(n1 <= _n1) { | |
_n1 += 10 | |
} | |
return _n1 - 5 | |
}() | |
r = n2 % 10 | |
range[1] = { () -> Double in | |
var _n2 = n2 - r | |
while !(_n2 < n2) { | |
_n2 -= 10 | |
} | |
return _n2 + 5 | |
}() | |
case (1.0, _): // 切り下げ -> 四捨五入または切り下げ | |
r = n1 % 10 | |
range[0] = { () -> Double in | |
var _n1 = n1 - r | |
while !(n1 <= _n1) { | |
_n1 += 10 | |
} | |
return _n1 | |
}() | |
r = n2 % 10 | |
range[1] = { () -> Double in | |
var _n2 = n2 - r | |
while !(_n2 < n2) { | |
_n2 -= 10 | |
} | |
return _n2 + 10 | |
}() | |
case (0.0, 0.0): // 切り上げ -> 切り上げ | |
r = n1 % 10 | |
range[0] = { () -> Double in | |
var _n1 = n1 - r | |
while !(n1 < _n1) { | |
_n1 += 10 | |
} | |
return _n1 - 10 | |
}() | |
r = n2 % 10 | |
range[1] = { () -> Double in | |
var _n2 = n2 - r | |
while !(_n2 <= n2) { | |
_n2 -= 10 | |
} | |
return _n2 | |
}() | |
case (0.0, _): // 切り上げ -> 四捨五入または切り下げ | |
r = n1 % 10 | |
range[0] = { () -> Double in | |
var _n1 = n1 - r | |
while !(n1 <= _n1) { | |
_n1 += 10 | |
} | |
return _n1 - 10 | |
}() | |
r = n2 % 10 | |
range[1] = { () -> Double in | |
var _n2 = n2 - r | |
while !(_n2 < n2) { | |
_n2 -= 10 | |
} | |
return _n2 | |
}() | |
default: | |
println("Exception in checkData : switch (offset1, offsst2) error") | |
println("self.offset1 => \(self.offset1)") | |
println("self.offset2 => \(self.offset2)") | |
} | |
range = range.map{ shiftDigitRight($0, self.pointPosition1) } | |
if (range[0].isSignMinus || range[1].isSignMinus) { // 上限もしくは下限がマイナスなら"なし" | |
return self.resultRange == nil | |
} | |
if self.resultRange == nil { return range[0] >= range[1] } // 下限が上限より大きいか同じなら"なし" | |
return self.resultRange!.map{ $0.description } == range.map{ $0.description } | |
} | |
} | |
// | |
// String.swift | |
// | |
import Foundation | |
extension String { // StringをDoubleにパースする | |
func doubleValue () -> Double { | |
return (self as NSString).doubleValue | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment