こんにちは。この記事はSwift Advent Calendar 2025 16日目の記事になります。
突然ですが、自分は数あるプログラミング言語の中でSwiftが好きです。ですが、なかなか書けていないのも事実です。
直近だとDroidKaigiの公式アプリチームに参加してたのでそこでSwiftUIを書いてたのと、FlutterKaigiの登壇ネタとしてAdd-to-appのベースを書いた程度です。普段の仕事ではFlutterかReactですし、Swift自体になかなか触れられていないというのが実情です。
そんな時、どこから見つけたかすら忘れてしまいましたが、こんなSwift Forumの投稿が目に入りました。
Advent Calendar急進派(自称)としても、元競技プログラマーとしても、Swiftを書くことを渇望しているものとしてもこの機会はまたとない機会でした。
というわけで無事期間は終了したので工夫したことをまず紹介し、その後各問題についてまとめていこうと思います。
実際のリポジトリはこちらです。
工夫した点
今回フォーラムに投稿されていたテンプレートを使ったのですが、いくつか使いにくい点もあったので以下の工夫をしました。
- 日毎のファイルを生成するSwiftスクリプトをvibe codingした
- 各日はpart1とpart2が存在しており、part1とpart2で返したい型を変えたい場合があったのでそれに対応した(元々part1とpart2が同じ型を返さないと動かなくなるようになっていた)
- Stringのsubscriptを用意した
これらの細かいところはAIに任せつつ、問題を解くコードは基本的には自分でやる形にしました。
各問題解説、あるいは感想
もし自分でやりたい方がいれば以降は見ないようにお願いします。
Day 1
問題
問題としてはダイアルをぐるぐると回し特定の条件を満たす回数を数えるというものでした。
一番問題の解釈に苦しんだものだった気がします。
Part 1
入力を順に処理しながら、ダイアルが0になる箇所を数えました。
Part 2
こちらも入力を順に処理するのですが、複数回カウントの必要があります。
超過した分に対して何回カウントする必要あるかを手元でシミュレートしてプログラムに落としました。
Day 2
問題
区間が与えられるのでその区間に含まれる特定条件の値を数えるような問題です。
Part 1
愚直に範囲内の数に対して条件を満たすかをチェックしていきました。
Part 2
こちらも基本的には条件が変わっただけなので同じようにチェックしていきました。
繰り返しを含むかどうかみたいなところはchunksを使って同じ長さに分割して、最初の要素と全て同じかみたいな確認をしてみました。
Day 3
問題
それぞれの文字列の中からルールにそって数字を抜き取り最大化するというような問題です。
Part 1
またもやchunksが登場し、数字にしていった上で左から最大値とそれ以降で一番大きい数をとっていきました。
Part 2
最大12桁ということは、左からn桁目を考えるときに最低でも右側に残り12-n桁の数字が残っていなければなりません。
そこに着目して左から1桁ずつ、取れる中で最大のものは何か?と探していき、最後の桁まで探索していきました。
Day 4
問題
特定条件でマップからロールをとっていく問題です。
Part 1
条件に合ってる場所を数えるだけなので隣接座標を作っておいて全て調べました。
Part 2
段々とマップの状況が変わっていくので、取ったところを別でフラグ立てしておき、取れなくなるまで無限ループさせました。
再帰関数だと別で用意するのはいらないかも。
Day 5
問題
区間がまた与えられるので、条件を満たすかどうかの判定や列挙をする問題でした。
Part 1
調べるだけなのでそのまま愚直に数えてます。
途中区間に入っているかどうかを判定するのに何やらテクい演算子が使われていますが、ここは書いてたらAIに補完されてしまいました。挙動あってるからまぁいっかと残しました。
Part 2
区間の被りを考えなければいけません。ですが左端がソートされていると被りを考える条件がシンプルになるため、ソートした上で被りをマージした全区間を探索、最後にその範囲を数えました。
Day 6
問題
特殊な形式で計算式が与えられるので、それを特定のルールで計算するみたいな感じです。
Part 1
Part 1のルールは単純なので、最後の演算子を元に計算していきました。
Part 2
こっちは入力値そのもののインデントが非常に大きな意味を持つ問題です。
テスト側にサンプル入力を貼ったらそれが崩れてつまづきましたがそれはさておき、今度は文字をそのまま左からなめていって演算子や空白で区切りを見つけて計算していきました。
Day 7
問題
マップが与えられるので、一定のルールで場合の数を数えるものです。
Part 1
こちらはシミュレートするだけなので、順を追って数え上げていきました。
Part 2
こちらは少しややこしいのですが、問題となっている線の伸ばし方は全てPart 1でシミュレートした線の選び方にすぎないので、一度マップを作ったのち、下から場合の数を足し上げていきました。
数学で一本道の場合の数を数えるときと似たような考え方です。
Day 8
問題
三次元空間の点群が与えられて、それを繋げていく問題です。
Part 1
繋げ方と距離をまず書き出して、ルール通りにシミュレートしました。
唯一微妙だなと思ったのが、答える問題とサンプルのループ数が違ったことで、テスト時と実行時に数値を変えなきゃいけないのが難点でした。
Part 2
こちらも基本的には別のシミュレートです。
サイズ1のSetの配列をあらかじめ用意しておき段々とマージしていくことで実現しました。
Day 9
問題
二次元平面の点情報が与えられて、そこから二点を対角線として作る四角形の条件に当てはまる最大の面積を求めるみたいな問題です。
Part 1
愚直に全ての面積を計算して最大値をとります
Part 2
ここで急に難しくなり、試行錯誤の上結果AIコーディングになりました...
最終的な解法としては、座標圧縮した上でどの点に色がつくかを計算し、その情報を使って条件に当てはまるかを判定して...という感じなのですが、今までほぼ貪欲だっただけに難易度が跳ね上がった印象でした。
ちなみに最初は四点が図形の内部にあるかで判定しようとしたところコーナーケースがあったり、座標圧縮しないで確認する方法を実装して実行が永遠に終わらなかったりなどの時間がありました。
Day 10
問題
難易度は着実に上がっていってます。
問題としては、ボタンとスイッチの状態みたいなのが与えられており、それぞれどういう風にボタンを押せるかを判定するものでした。
Part 1
こちらは比較的わかりやすく、最終ゴールがON/OFFの状態、すなわち2進数で表せるものであったため、各ボタンが操作できる場所を2進数で表し、さらに各ボタンを押すかどうかも2進数で表して、XORで計算してゴールに辿り着けるか?を確認していきました。
Part 2
今度はボタンを複数回押せるので、各場所が規定の回数操作されたか?を見ていく必要があります。
とりあえず上限回数はその中の最大値であることはわかって、単純に探していくことは容易なので小さいサンプルケースでは解けるのですが、実際の入力を処理できず...
自力ではAIを使っても正解に辿り着かなかったのでredditを見に行ったところ賢い解法を見つけました。
実際SwiftでPart1のロジックを再利用して実行したところかなり時間はかかったのですが、ちゃんと実行が終わるようなプログラムになりました。
Day 11
問題
Day11は急に簡単になりました。幅優先で再帰を回すだけの問題になります。
Part 1
めちゃくちゃ単純ですね。関数内に関数が書けてしまうことがこういう時にはありがたくなります笑
Part 2
こっちは愚直にやると終わらなくなるのでちょっとメモ化してあげて枝刈りをします。
Day 12
問題
最後は盤面に二次元の図形が埋められるかどうかを判定するというPart1からだいぶ難易度の高い問題です。
しょっぱなからAIくんの出番です...と思ったのですが、こちらもAIだと解き切れず、redditを頼りました。
この公式投稿に解法が集まっていそうだったのでDiaにわかりやすいものをピックアップしてもらったところ衝撃の事実が
プレゼントの形はすべて3×3に収まります。領域の幅と高さをそれぞれ3で割った整数値の積は、必ず置けるプレゼント数の下限になります。合計個数がその下限以下なら『必ず入る』と判定できます。逆に、各形の#数×個数を合計した総タイル数が領域の面積を超えていれば『絶対に入らない』ので除外します。実入力ではこの2つの単純なチェックだけで十分でした。
...え?
どうやら例題だとNP困難な探索を必要としますが、本番データだとそこまでする必要はないとのことです。なんだそりゃ。
解法
これを愚直に信じて実装してみました。例題は解けないと思うので実際のデータでのみ試しています。
本当にこれで解けました...
まとめ
というわけで、自力で最後まで...とはいかなかったですが、さまざまな力を借りて完走することができました。
結果としてはSwift Leaderboardで16位でした。
最後の問題がなぜかイージー入力になっていたり、普段の競プロにあるようなTLEが基本自分のパソコンの処理能力依存だったりと純粋な競プロではないのですが、ひさびさに感覚を思い出して楽しかったです。
またAIの力と無力さを同時に感じたのも特徴だったかなと思います。NP困難だけど実はこう解けるでーなんてそもそもの設定がずるかったりしますが、Day10のPart2の解法とかはAIから引き出せなかった賢いやり方だったので人間ってやっぱりすごいなと感じました。
めでたしめでたし。

