forked from trainline-eu/csa-challenge
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcsa.swift
124 lines (109 loc) · 3.91 KB
/
csa.swift
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
import Foundation
typealias Station = Int
protocol InputType {
func read(count: Int) throws -> [Int]?
}
struct Error: ErrorType {
let message: String
init(_ message: String) {
self.message = message
}
}
struct Connection {
let from: Station, to: Station, departure: time_t, arrival: time_t
init?(input: InputType) throws {
guard let values = try input.read(4) else { return nil }
from = values[0]
to = values[1]
departure = values[2]
arrival = values[3]
guard from >= 0 && to >= 0 else { throw Error("Station number cannot be negative.") }
guard arrival >= departure else { throw Error("Time travel is not supported yet.") }
}
}
struct Request {
let from: Station, to: Station, departure: time_t
init?(input: InputType) throws {
guard let values = try input.read(3) else { return nil }
from = values[0]
to = values[1]
departure = values[2]
guard from >= 0 && to >= 0 else { throw Error("Station number cannot be negative.") }
}
}
struct Router {
private let connections: [Connection]
private let count: Int
init(input: InputType) throws {
var connections: [Connection] = []
while let connection = try Connection(input: input) {
connections.append(connection)
}
self.connections = connections
self.count = connections.reduce(0) { (count, connection) in
max(count, connection.from + 1, connection.to + 1)
}
}
func solve(request: Request) -> [Connection] {
let from = request.from, to = request.to, departure = request.departure
guard count > max(from, to) else { return [] }
var incoming: [Connection?] = Array(count: count, repeatedValue: nil)
for connection in connections {
if connection.departure < departure || connection.to == from {
continue
}
if let final = incoming[to] where connection.departure > final.arrival {
break
}
if let current = incoming[connection.to] where connection.arrival > current.arrival {
continue
}
if connection.from == from {
incoming[connection.to] = connection
} else if let previous = incoming[connection.from] where connection.departure > previous.arrival {
incoming[connection.to] = connection
}
}
var route: [Connection] = []
var station = to
while let connection = incoming[station] {
route.insert(connection, atIndex: 0)
station = connection.from
}
return route
}
}
struct TextualInput: InputType {
private let body: () -> String?
init(_ body: () -> String?) {
self.body = body
}
func read(count: Int) throws -> [Int]? {
guard let line = body() else { return nil }
guard !line.isEmpty else { return nil }
let components = line.utf8.split(0x20)
guard components.count == count else { throw Error("There should be exactly \(count) values on this line.") }
return try components.map { component in
guard let string = String(component), let integer = Int(string) else { throw Error("\"\(component)\" is not an integer.") }
return integer
}
}
}
func printRoute<S: SequenceType where S.Generator.Element == Connection>(route: S) {
for connection in route {
print("\(connection.from) \(connection.to) \(connection.departure) \(connection.arrival)")
}
print("")
fflush(stdout)
}
do {
let input = TextualInput({ readLine() })
let router = try Router(input: input)
while let request = try Request(input: input) {
let route = router.solve(request)
printRoute(route)
}
} catch let error as Error {
fputs("\(error.message)\n", stderr)
exit(1)
}