※過去記事はこちら。AlteryxユーザーのためのAdvent of Codeの始め方、1日目
2日目です。
タイトルは、「Rock Paper Scissors」、、、「じゃんけん」ですね!
2問目は、正直クイズ文の英語で惑わされました・・・。Advent of Codeの文章はGoogle翻訳やDeepLでも変な翻訳になることが多く、結局原文読まないと意味がわからん、ということが多いです。
で、今回はじゃんけんの問題です。RockはScissorsに勝ち、ScissorsはPaperに勝ち、PaperはRockに勝ちます。じゃんけんの勝ち負けでもらえるポイントが異なっており、じゃんけんの手としてどの手をだすかでも得点が異なります。これを整理すると、
勝ち・負け得点
- 勝ち:6点
- 引き分け:3点
- 負け:0点
手による得点
- Rock:3点
- Paper:2点
- Scissors:1点
入力データとしては、以下のようになっています。
A Y
B X
C Z
意味するところは、Part1とPart2で変わりますが、エルフがじゃんけんで勝つための戦略とのことです。
・ネ
・
・タ
・
・バ
・
・レ
Part1を解いてみる
Part1での入力データはそのままじゃんけんで何を出すか、ということを示しています。
X、Y、Zは自分の手、A、B、Cは相手の手です。アルファベットの前からRock、Paper、Scissorsとなっています。
これらの情報を使って入力データから得られる得点の合計を計算します。つまりサンプル入力であれば、以下のようになります。
A Y → Rock vs Paper(2pt) → 勝ち(6pt) → 8pt
B X → Paper vs Rock(3pt) → 負け(0pt) → 3pt
C Z → Scissors vs Scissors(1pt) → 引き分け(3pt) →4pt
合計としては15点となります。
これをAlteryxで実現していけばいい、ということになります。ちなみに、ここまでを整理するのがなかなか1日目と比べて時間のかかるポイントです(とはいえ、正確に問題文が把握できればロジックに落とすのは難しいわけではありません)。
アプローチは、いくつかあると思いますが、問題文を表現した対応表を使って結合していくか、ひたすらIF文で条件をつけていくか、の2パターンになるかと思います。
なお、この入力データは2500行あるのですが、パターンとしてはたったの9パターン(組み合わせ)しかありません。まぁ、(X,Y,Z)x(A,B,C)の組み合わせなので当たり前なのですが・・・。これを考えるとそれほど複雑に考えなくても簡単に勝ち負け得点表を作ることが可能です。
対応表パターン
対応表として、A-C、X-Yと手(Rock~Scissors)で何点もらえるか「HandPoint」表と、Rock~Scissorsでどのパターンでどのような勝ち負けのポイントになるか「winning_pattern」という2つの表を作って対応したのが以下のワークフローです。
HandPoint表:
winning_pattern表:
今回はこの表がさくっとできればできたも同然に感じましたが、残念ながらライブでやっていた時はこの表を混乱しながら作っていたのであまりきれいではありませんでした。
IF文メインで攻める方法
今度はIF文メインでやってみます。
とはいえ、これ一度作ったあとに思いついた方法なのでものすごい整理されていますが、結構みなさんIF文のネストで苦労されていたようです。
ワークフローは以下の通りです。
IF文の中身は以下のとおりです。
ToNumber(
Switch(Right([Input],1),"0",
"X","1",
"Y","2",
"Z","3"
))
+
ToNumber(
IF [Input] IN ("C X","A Y","B Z") THEN "6"
ELSEIF [Input] IN ("A X","B Y","C Z") THEN "3"
ELSE "0"
ENDIF
)
ちなみに、IF文自体を他の関数で囲んだりIF文+IF文といったことも可能です。複数行に見えますが、IF文の返す結果は単なる値です。
これは、Xなら1点、Yなら2点、Zなら3点というものとA-C、X-Zの組み合わせで勝ちパターン、引き分けパターン、負けパターンそれぞれで6点、3点、0点と判断しているだけですので、非常にシンプルな式になっています。
Part2を解いてみる
Part2はインプットデータの読み取り方が変わります。
自分の手であったX-Zは実は勝つべきか、負けるべきか、を示唆するデータとなっており、Xなら勝ち、Yなら引き分け、Zなら負け、ということになりました。
A Y → 引き分け(3tp)→ 相手がRockなので、引き分けるには Rock(1pt) → 4pt
B X → 負け(0pt) → 相手がPaperなので、負けるにはRock(1pt) → 1pt
C Z → 勝ち(6pt) → 相手がScissorsなので勝つにはRock(1pt) → 7pt
合計12点となります。
これをワークフローに落とし込んでいきましょう。
対応表パターン
対応表としては、まずX~Zの勝ち負けのパターンである「Winning Point」、相手の手を示す「Hand」、相手の手と勝ち負けのパターンから自分の手とポイントを決める「winning_pattern」という3つの表を準備して望みます。
ワークフローは以下の通りとなります。
「Winning Point」:
「Hand」:
「winning_pattern」:
繋がりがわかりにくいので、結論としては以下のようにひも付きます。
データソースのCountと(winning_pointとX-Z Point)を足したものを掛け算したものを集計したものが最終的な解答です。
IF文メインに攻める
IF文もこれまでのロジックをまとめるだけです。
計算式はPart1用のフォーミュラツールの中に埋め込んでいます。
ToNumber(
Switch(Right([Input],1),"0",
"X","0",
"Y","3",
"Z","6"
))
+
ToNumber(
IF [Input] IN ("A X","C Y","B Z") THEN "3"
ELSEIF [Input] IN ("C X","B Y","A Z") THEN "2"
ELSE "1"
ENDIF
)
基本的な計算式はPart1と全く同じで、X~Zの点数が異なるのと、勝ち負けの組み合わせが異なるだけです。
まとめ
- 2日目は紐解くとシンプルでしたが、組み合わせはある程度手動になってしまいます
- 最速の人でも16分程度かかっています。
- 個人的には、どのようなパターンを作ればいいのか、どこまで手動で表にするのか、どこからロジックでやるのか、そのあたりの見極めに時間がかかったように思います。
- 個人タイム:Part1 32分51秒、Part2 48分10秒
コメント