Skip to content

Instantly share code, notes, and snippets.

@all-user
Created February 2, 2015 04:18
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 all-user/7886df0b9563fe70f5c3 to your computer and use it in GitHub Desktop.
Save all-user/7886df0b9563fe70f5c3 to your computer and use it in GitHub Desktop.
CodeIQ 「中学入試から:概数と計算」提出コード
//
// 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