
Swiftで月次カレンダーの表示アルゴリズム(1)
自作アプリReminbanにカレンダー機能を統合しようと考えているのですが、以下のようなちょっと気の利いた表示の仕方をするにはひと工夫必要です。

要は期間を持つ予定があったとき、それが他の予定と重ならないよう、うまく並べてあげる必要があるのです。調べてみたところ、このページが見つかりました!
しかもCode golf(いかに少ないバイト数で実装できるか)しててすごいw
Pythonのリファレンス実装のリンクがあったので、これを参考にしようと考えました。これをChatGPT先生にSwiftコードへ変換してもらったのがこちら。
import Foundation
// イベントを表すタプル (開始日, 終了日) のリストを受け取り、
// それをアルファベット順にラベル付けしてスケジュールを出力する関数
func scheduleEvents(events: [(Int, Int)]) {
let alphabet = Array("ABCDEFGHIJKLMNOPQRSTUVWXYZ")
var namedEvents: [(start: Int, end: Int, name: Character)] = []
// 各イベントにアルファベットの名前を割り当てる
for (index, event) in events.enumerated() {
if index < alphabet.count {
namedEvents.append((event.0, event.1, alphabet[index]))
} else {
break // アルファベットが尽きたら終了
}
}
// ソート: 開始時間が早い順、終了時間が遅い順、アルファベット順
namedEvents.sort { ($0.start, -$0.end, $0.name) < ($1.start, -$1.end, $1.name) }
// 1レーンを初期化する関数
func initializeLane() -> [Character] {
return Array(repeating: "~", count: 7) // 7日間のスケジュール
}
var lanes: [[Character]] = [initializeLane()]
// 各イベントをレーンに配置
for event in namedEvents {
var placed = false
for i in 0..<lanes.count {
if lanes[i][event.start...event.end].allSatisfy({ $0 == "~" }) {
lanes[i].replaceSubrange(event.start...event.end, with: Array(repeating: event.name, count: event.end - event.start + 1))
placed = true
break
}
}
// すべてのレーンが埋まっていたら新しいレーンを作成
if !placed {
var newLane = initializeLane()
newLane.replaceSubrange(event.start...event.end, with: Array(repeating: event.name, count: event.end - event.start + 1))
lanes.append(newLane)
}
}
// スケジュールを出力
for lane in lanes {
print(String(lane))
}
}
Swift Playgroundで動かしたらPythonと同じ結果を出力していたのでLGTM👍
「レーン」を用意し、その中に一週間の予定をうまく入れていくアルゴリズムでした。これを月次カレンダーとしてきれいに表示するにはもうひと工夫必要なので、次回に続きます!