Advent of Codeをデータ分析ツールAlteryxでやってみるシリーズ、2025年10日目です。
※過去記事はこちら。AlteryxユーザーのためのAdvent of Codeの始め方、1日目、2日目、3日目、4日目、5日目、6日目、7日目、8日目、9日目。

Day 10「Factory」
タイトルは「工場」。
廊下の先にあるのは工場でした。この工場の機械はオフラインになっているため、これを起動する必要があるようです。初期化手順は、なぜか柴犬に食べられてしまったということで、ライトのダイアグラム図、ボタンの配線図、それぞれの機械の要求電圧(joltage)のみとのことです。
実際のサンプルは以下のとおりです。
[.##.] (3) (1,3) (2) (2,3) (0,2) (0,1) {3,5,4,7}
[...#.] (0,2,3,4) (2,3) (0,4) (0,1,2) (1,2,3,4) {7,5,12,7,2}
[.###.#] (0,1,2,3,4) (0,3,4) (0,1,2,4,5) (1,2) {10,11,11,5,10,5}
カギ([])括弧はライトのダイアグラム図、丸括弧はボタンの配線図、中括弧({})は電圧(Joltage)です。
ライトは、#が点灯です。初期状態はすべて消灯しています。つまり[.##.]は、0番目と3番目は消灯、1,2番目は点灯ということです。
電圧は、{3,5,4,7}となっていると、0番目が3、1番目が5、2番目が4、3番目が7を示します。
ボタンですが、丸括弧の数だけボタンがあり、丸括弧内は、押した時に何番目のライト/電圧が反応するか、ということです。(1,3)だと、1番目と3番目が同時に押されたことになります。
押すと、ライトは点灯します、点灯していれば消灯します。いわゆるトグルスイッチですね。電圧は、押すたびに+1されます。
Part1では、示されているライトのパターンになるようにボタンを押します。どれを何回押すか、ということですが、組み合わせは何通りもありますが、最も押す回数が少ないものを探します。その回数をすべての機械に対して行った時の合計が求めるクイズの答えです。
Part2では、電圧を見ていきます。これも最小になるボタンの押下回数をカウントし、合計します。
・ネ
・
・タ
・
・バ
・
・レ
Part1、2を解いてみる
まず、ライト、ボタン、電圧をどのようなデータとして持つか、そこをまず検討する必要があります。
まず、Part1ですが、ライトとボタンを使います。
ライトの方は、[.##.]みたいなのだと使いにくいので、ライトの点灯の場所を数値にしてカンマ区切りで持つことにしました。この例だと、「2,3」です。ボタンについてはPart1,2ともに同じですが、完全に縦持ちにしています。
ライト:

ライトの数がないと困るので、ライトの総数を持っています。また、ボタンの数も持っています。
ボタン:

これを反復マクロ内で処理しますが、ライトは現在の状態を持っているため、初期は消灯なので空っぽです。これに対して各ボタンをすべて押してみます。それにより、ライトの状態が変化しますが、それが提示されているランプのパターンと一致すれば終了、ということにしています。
ボタンを押すということをどうやって再現するか、ちょっと悩みポイントでしたが、現在の点灯状況と、ボタンをユニオンしておき、各ライトのポジションのカウントを取った時に奇数なら点灯、ということをやっています。現在の状態を保持しているデータは、ボタンのパターン数分のデータが必要になるので、行生成ツールでデータを増やしています。また、元データは各試行でボタンの数だけパターンが増えるので、ボタンデータは、それまでに倍増したパターンの数だけ増やしています。これらをユニオンしてカウント、奇数になるものだけ残して、点灯状態を比較すればクリアできます。

終了条件として、点灯パターンと現在のパターンが一致した機械はすべて終了させる仕組みを入れています。今回は、ボタンの押下数が7回でクリアできましたが、それでもワークフローの実行時間は53秒かかっています。

Part2では、ボタンを押す回数が多いため、パターンが増えすぎ、組み合わせ爆発が起こってしまいます。そこで何かしらアルゴリズムが必要になります。
一つのデータに着目します。
[.##.] (3) (1,3) (2) (2,3) (0,2) (0,1) {3,5,4,7}
ボタン部分(赤色)と電圧(水色)を使いますが、以下のような方程式として考えることができます。
n5+n6=3
n2+n6=5
n3+n4+n5=4
n1+n2+n4=7
これを解けばいいのですが、これはいわゆる組み合わせ問題です。つまり、最適化ツールが使えるということです。
上の例を解くために、最適化ツールに以下のように入れれば良いです。
O入力:

A入力:

B入力:

これにより、以下のように解かれます。

つまり、Objective Valueの10が正解となります。
これをすべての機械に対して行い、出た値の合計を取ればオッケーです。そのためには、元のデータをうまく加工してこの形にする必要があります。
やっかいなポイントとしては、A入力の項目数が電圧の数となるのですが、これが変化するということです。基本的に列の数が変化するものは苦手です(基本、変わらない前提ですよね)。普通にやると、最も電圧の多いものがベースとなり、あとは一列全部Nullとかになってしまいます。
最適化ツールはグループ化処理ができないため、バッチマクロの中に入れないと複数の問題に答えられません。なので、今回はバッチマクロで渡す時に、テーブルデータを1セルに固めた状態でコントロールパラメータ入力に渡しています。

こんな感じです。
これの展開はそんなに難しくないです。改行で行に分割し、カンマで行に分割したのちにクロスタブでテーブル形式にしたあとに動的リネームで1行目を名前にすれば完了です。データの型も直しておく必要があります。
マクロの中はこのような感じになります。

これより、一つに固める方が難しいですね。
最適化ツールの上からテーブルA、B、Cとしましたが、AとCはすぐにできます。Aはほぼ固定値で、ボタンの数が異なるだけです。Cはvoltageを少し変形するだけです。Bみたいな行列を作るのは少し面倒です。対応する部分を赤く囲んでみました。

基本的に、Bのような横が可変のテーブルを作るには、すべてデータを縦持ちにしておいて、これをうまくConcatenateしていくのがコツです。

これにより、クイズの答えが得られますが、さすがに時間が少しかかりだいたい16分程度で答えがでました。
ワークフロー全景です。

まとめ
- Base A原理主義的にはRベースツールも禁止とのことなので、最適化ツールを使わずにどうにかしたい、という人もいらっしゃいます
- が、最適化ツール好きなので使っちゃいますよね(一応BaseAのはず)
- しかし、使わない場合、どうやって解くか、、、位置最適化マクロでがんばるか?それとも何かしら別のロジックを使うのか・・・
- 時間のあるときに挑戦してみようと思います

コメント