※過去記事はこちら。AlteryxユーザーのためのAdvent of Codeの始め方、1日目、2日目、3日目、4日目。
第五話 「If You Give A Seed A Fertilizer」
タイトルは「種子に肥料を与えると」。「ひどい目にあいます」と言いたい・・・。
前回、ふわっと島がどうのこうのというコメントはあったと思うのですが、ボートに乗って新しい島へ渡り庭師を見つけたところからストーリーは始まります。どうやら次はフェリーに乗るようなのですが、その前に解決するべき課題が与えられています。
今回は食糧生産の問題を解決するために、植えるべき種のリストと、それを育てるために必要なもののリストがインプットとして与えられました。以下のようなものです。
seeds: 79 14 55 13
seed-to-soil map:
50 98 2
52 50 48
soil-to-fertilizer map:
0 15 37
37 52 2
39 0 15
fertilizer-to-water map:
49 53 8
0 11 42
42 0 7
57 7 4
water-to-light map:
88 18 7
18 25 70
light-to-temperature map:
45 77 23
81 45 19
68 64 13
temperature-to-humidity map:
0 69 1
1 0 69
humidity-to-location map:
60 56 37
56 93 4
正直このインプットを見た時点で頭痛がします。変換だけでも結構大変です。
さて、最初の1行目「seeds: 79 14 55 13」は、植えるべき種のリストです。79、14、55、13と4つあります。
残りの部分は、マップです。例えば「seed-to-soil map:」であれば、seedからsoilへのマッピング表です。ややこしいのが、
50 98 2
52 50 48
とあると、最初の数値は宛先、次がソース、次が範囲となります。つまり、宛先は50から範囲2(50、51)となっており、ソースは98から範囲2(98、99)となっています。下の行はまた別の範囲を示しています。つまり、わかりやすくするために、seed側が左、soil側を右とすると、
50 52 ※2行目に対応
51 53 ※2行目に対応
52 54 ※2行目に対応
53 55 ※2行目に対応
・ ・
・ ・
・ ・
97 99 ※2行目に対応
98 50 ※1行目に対応
99 51 ※1行目に対応
となります。直感的にマッピング表と左右が入れ替わってるのでわかりにくいですよね。なお、この表に該当しないものは、同じ値でマッピングされます。
よくよく考えると、範囲でそのまま別の範囲にマッピング表の通りスライドするだけの話ではあるのですが、どこで区切られるのかわからないので、思った以上に複雑です。
さて、Seedから最後のlocationまで変換した時、最後のlocationに変換したときに一番小さいものを探しましょう。というのが今回のクイズの回答になります。
次に、みんなの頭を悩ませたPart2ですが、Seedの数も範囲で示されていた、ということです。つまり、seeds: 79 14 55 13、であれば、79から範囲14まで、、、つまり79から92までと、55から範囲13の67まで、ということになります。つまりマッピング表は変わらないのですが、インプットの数がめちゃくちゃ増えて、全然終わらない、ということになるわけです。
・ネ
・
・タ
・
・バ
・
・レ
Part1を解いてみる。
Part1は丁寧に解いていくだけです。最初に与えられる表が面倒なので、ここを綺麗にするだけでも一苦労です。
まず、Seed Listです。
次にマップリストです。
最後は、なくても問題ないのですが、各ステージ(Map)のリストです。これは繰り返しマクロないで上から順に一つづつフィルタをかけて次のターゲットを綺麗にするために使っています。
ワークフロー外観です。
反復マクロです。
素直にマップを当てていっています。途中の経路も出すようにしています。
Part2を解いてみる
ここからが本番です(Part1時点でも5日目では難易度高すぎですが・・・Part1ですら昨年の後半戦くらいの難易度ですね)。
入力をPart1と同じように加工すればそのままできるじゃん?と思うでしょう。実際行生成で作ればサンプルデータは素直に通ります。しかし、本番データになると、数が膨大すぎて1億行を超えるSeedが生成され、反復マクロが全然進まない、という現象に陥ります。
つまり、インプットもばらさずに範囲で動くように改造してあげる必要があります(他の方法でもいけるかもしれません)。
初期段階に作ったものはこちら。1ステップずつロジックを継ぎ足して作っていって最後標準マクロにまとめたのがこちらです。
これだとカッコ悪いので、、、反復マクロ化しました。
マクロは以下のとおりです。
大きく分けて上側と下側のブロックに別れています。上は来た範囲がまるっとそのまま行ける場合。下側は、部分的にしかかぶらないところがあるケース(来た範囲が2つに分かれるケース)です。もっと複雑なデータだとこの場合分けでは不完全かもしれませんが、たまたま?うまくいっています。
(そして、マクロ完了後の検査も、レコードが一番小さいところしか見ていません。論理的にはそれでオッケーですが、0始まりの範囲だけは取り除く必要がありました。考慮漏れなのかなんなのかはわかりません)
まとめ
- Part1は比較的めんどくさいですが、素直にマッピング表で総当りすると解けます。解けるだけで簡単とは言わないです。基本は反復マクロ必須な感じです(でも、6段しかないのでマクロじゃなくてロジック作ってコピーでもなんとかなるレベル(Designer Cloudでもできそうだな・・・)。
- Part2は雑にやらずに、真面目にイチから組み直した方が早かったですね・・・。悩んで試行錯誤していた時間の方が長かったです。ただ、反復マクロ化する気にならなかったので、雑に標準マクロを6個並べました。その後綺麗にしてアップしましたが。ちなみに、0っていうのが最終結果にいて、それだけは取り除きました。
- 5日目のみだと13位。Part1だけなら6位だったんですが、Part2で大苦戦して、なんとかギリギリ解けた感じです。Part1も1時間13分かかっています。1位の人は、Part1で34分、Part2でもそこから1時間くらいで解いています。実質これ、Part2は作り直しみたいなものでした。いずれにしても、阿鼻叫喚の悲鳴しか聞こえてこなかった5日目(Alteryx以外の通常の言語でやってる人も大苦戦みたいです)、、、勘弁してほしかったです。
コメント