今いちばん話題の、貴族向けの新しいマッチングアプリNoble Knotsの開発に携わることになりました! 何世紀にもわたる王族同士の結婚のせいで、事態は…_複雑_になってしまいました。おっと、私たち双子だった という事態を避けるために、2人がどれくらい近い親戚なのかを調べるシステムを作るのが仕事です。
Noble Knotsは、アイスランドの「Islendinga-App」に着想を得ています。これは、アイスランドへの入植の時代までさかのぼり、アイスランド人の間に知られているすべての親族関係をたどるデータベースに支えられています。このアルゴリズムは、王家の家系図の中で2人の間の血縁の度合いを求めます。
このアプリは、完璧な相手に王冠を授ける手助けになるでしょうか?
課題は、家系図の中の2人の人物の間の隔たりの次数を求めることです。 これは、ハリウッドの俳優は誰でもケビン・ベーコンから6次以内にいる、というポップカルチャーの考え方に似ています。
次のような家系図があるとします。
┌──────────┐ ┌──────────┐ ┌───────────┐
│ Helena │ │ Erdős ├─────┤ Shusaku │
└───┬───┬──┘ └─────┬────┘ └────┬──────┘
┌───┘ └───────┐ └───────┬───────┘
┌─────┴────┐ ┌────┴───┐ ┌─────┴────┐
│ Isla ├─────┤ Tariq │ │ Kevin │
└────┬─────┘ └────┬───┘ └──────────┘
│ │
┌────┴────┐ ┌────┴───┐
│ Uma │ │ Morphy │
└─────────┘ └────────┘
TariqとUmaの隔たりの次数は2です(Tariq → Isla → Uma)。 IslaとKevinの間には知られた関係がありません。与えられたデータに接続がないためです。 UmaとIslaの隔たりの次数は1です。
IslaとTariqは兄弟で、隔たりの次数は1です。 同じように、この実装では、自分と父の兄弟との隔たりの次数は2であると報告されます。
この演習のテストでは、解答をPythonのRelativeDistanceというclassとして実装することを想定しています。
Pythonのclassに慣れていない場合は、classesやPython公式ドキュメントのclassesから始めるのがおすすめです。
RelativeDistanceは、family_treeを使って初期化する必要があります(詳しくは__init__()を参照してください)。family_treeは、keysが個人、valuesがその個人の子どものlistである辞書です。
また、degree_of_separationメソッドも実装する必要があります。これは、渡された家系図に含まれる個人person_aとperson_bの間の分離度を返します。
RelativeDistanceクラスのインスタンスを作成するために使われる__init__特殊メソッドのスタブと、degree_of_separationメソッドのスタブが用意されています。
まず、family_treeのデータを表す適切な属性をself(インスタンス)に持たせるように、__init__をカスタマイズします。
次に、degree_of_separationメソッドにロジックを追加して、person_aとperson_bの間の分離度を計算します。
例外を送出する必要があることもあります。 その際は、エラーの原因が何であるかを示す意味のあるエラーメッセージを必ず含めましょう。 これによりコードが読みやすくなり、デバッグも格段に楽になります。 エラーの原因が特定の種類になるとわかっている場合は、組み込みのエラー型のいずれかを送出しても構いませんが、その場合も意味のあるメッセージを含めるようにしましょう。
この演習では、複数のValueErrorを「送出」するためにraise文を使う必要があります。
最初のシナリオでは、RelativeDistance.degree_of_separationメソッドに渡された人物のどちらか、または両方が家系図に存在しない場合に、ValueErrorを送出する必要があります。
# Example when Person A is not in the tree.
raise ValueError("Person A not in family tree.")
両方の人物が家系図に存在する場合は、ルールで定義された有効なつながりが2人の間にないときに、ValueErrorを送出する必要があります。
# Example when there are no valid connections.
raise ValueError("No connection between person A and person B.")
テストが通るのは、期待されるexception型をraiseし、それに期待されるメッセージを含めた場合だけです。
この説明はすべてを網羅しているわけではないので、テストとその期待される結果をよく確認してください。