Skip to content

Instantly share code, notes, and snippets.

@notcome
Created January 1, 2017 20:05
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 notcome/6840291157587972b9930672581340d0 to your computer and use it in GitHub Desktop.
Save notcome/6840291157587972b9930672581340d0 to your computer and use it in GitHub Desktop.
An example of how to employ modern syntactic sugars in writing ACM ICPC code.
// POJ 1093
// This problem asks us to justify monospaced texts with a given width.
// For details, see http://poj.org/problem?id=1093.
let email = "Writing e-mails is fun, and with this program, they even look nice."
let width = 25
let words = email.characters.split(separator: " ").map { String($0) }
let metrics: [Int] = words.map { $0.characters.count }
func square(_ x: Int) -> Int {
return x * x
}
struct Line {
let subrange: ClosedRange<Int>
let words: ArraySlice<String>
let metrics: ArraySlice<Int>
let gapCount: Int
let gapInfo: (basicGapWidth: Int, basicGapCount: Int, expandedGapCount: Int)?
let badness: Int
init?(words: [String], metrics: [Int],
subrange: ClosedRange<Int>, width: Int) {
self.subrange = subrange
self.words = words[subrange]
self.metrics = metrics[subrange]
guard subrange.count > 1 else {
self.gapCount = 0
self.gapInfo = nil
self.badness = self.metrics.first! == width ? 0 : 500
return
}
self.gapCount = subrange.count - 1
let totalGapWidth = width - self.metrics.reduce(0) { $0 + $1 }
guard totalGapWidth >= gapCount else { return nil }
let basicGapWidth = totalGapWidth / gapCount
let expandedGapCount = totalGapWidth - basicGapWidth * gapCount
let basicGapCount = gapCount - expandedGapCount
self.gapInfo = (basicGapWidth, basicGapCount, expandedGapCount)
self.badness = basicGapCount * square(basicGapWidth - 1) + expandedGapCount * square(basicGapWidth)
}
var line: String {
guard let gapInfo = self.gapInfo else { return self.words[self.words.startIndex] }
var line = ""
let basicGap = String(repeating: " ", count: gapInfo.basicGapWidth)
let expandedGap = basicGap.appending(" ")
for i in 0..<self.gapCount {
let gap = i < gapInfo.basicGapCount ? basicGap : expandedGap
line.append(words[words.startIndex + i].appending(gap))
}
line.append(self.words[self.words.endIndex - 1])
return line
}
}
var table = [(line: Line, badness: Int)]()
table.reserveCapacity(words.count)
for i in 0..<words.count {
var line: Line?
var minBadness = 0x0fffffff
for j in (0...i).reversed() {
guard let newLine = Line(words: words, metrics: metrics, subrange: j...i, width: width)
else { break }
let previousBadness = j > 0 ? table[j - 1].badness : 0
let newBadness = newLine.badness + previousBadness
if newBadness < minBadness {
minBadness = newBadness
line = newLine
}
}
table.append((line!, minBadness))
}
var index = table.count - 1
var lines = [String]()
repeat {
let line = table[index].line
lines.append(line.line)
index = line.subrange.lowerBound - 1
} while index > 0
for line in lines.reversed() {
print(line)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment