Lab5: 継承

この Lab では1~2人のクラスメートと協力することは問題ありませんが、そのグループのすべての受講生が等しく実習に貢献することが求められます。

家族の各メンバーの血液型の継承をシミュレートします。

$ ./inheritance
Child (Generation 0): blood type OO
    Parent (Generation 1): blood type AO
        Grandparent (Generation 2): blood type OA
        Grandparent (Generation 2): blood type BO
    Parent (Generation 1): blood type OB
        Grandparent (Generation 2): blood type AO
        Grandparent (Generation 2): blood type BO

背景

人の血液型は2つの対立遺伝子 (異なる形態の遺伝子) によって決まります。可能性のある3つの対立遺伝子はA、B、Oであり、それぞれの人は2つ (同じかもしれないし、違うかもしれません) をもちます。子供の両親はそれぞれ、2つの血液型対立遺伝子の1つを子供にランダムに渡します。したがって、考えられる血液型の組み合わせは、OO、OA、OB、AO、AA、AB、BO、BA、およびBBです。

たとえば、片方の親の血液型がAOで、もう一方の親の血液型がBBである場合、それぞれの親からどの対立遺伝子を受け取るかによって、子の血液型はABまたはOBになります。同様に、片方の親の血液型がAOで、もう一方がOBである場合、子の血液型はAO、OB、AB、およびOOになります。

始め方

VS Codeを開きます。

ターミナルウィンドウ内をクリックすることから始めて、それからcdを実行します。
その後プロンプトは次のようになっていることがわかります。

$

ターミナルウィンドウの内側をクリックし、次のように入力します。

wget https://cdn.cs50.net/2021/fall/labs/5/inheritance.zip

その後にEnterを押すと、inheritance.zipというZIPがあなたのCodespaceにダウンロードされます。wgetと次のURLの間にあるスペースや、その他の文字を見落とさないように注意してください。

次に

unzip inheritance.zip

を実行して、inheritanceというフォルダを作成します。
ZIPファイルは不要になったため、

rm inheritance.zip

を実行し、プロンプトで “y “に続いてEnterで応答すると、ダウンロードしたZIPファイルが削除されます。

次に

cd inheritance

の後にEnterを押して、そのディレクトリに移動する(つまり、開く)。これでプロンプトは以下のようになります。

inheritance/ $

すべて成功した場合は、次のように実行します。

ls

すると、inheritance.c というファイルが表示されます。

もし問題が発生した場合は、もう一度同じ手順を踏んで、どこが間違っていたかを確認してください

理解を深める

inheritance.cの配布コードを見てください。

person という型の定義に注目してください。各 person は2つの親の配列を持ち、それぞれが別の person 構造体へのポインタになります。それぞれの人は2つの対立遺伝子の配列をもち、それぞれがchar ('A''B'、または'O') で表されます。

では、main関数を見てみましょう。この関数は、乱数生成器を「シード」する (すなわち、いくつかの初期入力を提供する) することから始まります。この乱数生成器を使って、あとでランダムな対立遺伝子を生成します。次に、main 関数は create_family 関数を呼び出して、3世代 (すなわち、本人とその両親、祖父母) の家系に対する person 構造体の作成をシミュレートします。次に print_family を呼び出して、それぞれの家族とその血液型を出力します。最後に、この関数は free_family を呼び出して、malloc で割り当てられていたメモリを解放します。

create_family 関数と free_family 関数の作成があなたの課題です。

実装の詳細

inheritance.c の実装を完了して、特定の世代サイズの家系を作成し、各家系のメンバーに血液型対立遺伝子を割り当てます。最も古い世代には、ランダムに対立遺伝子が割り当てられます。

  • create_family 関数は整数 (世代) を入力として受け取り、 (mallocを介して) その世代数の家族の各メンバーに対して1人を割り当て、最も若い世代の人へのポインタを返します。
    • 例えば、create_family(3) は両親が2人いる人へのポインタを返さなければなりません。
    • 各個人には対立遺伝子が割り当てられていなければなりません。最も古い世代はランダムに ( random_allele 関数を呼び出すなどして) 対立遺伝子をもち、若い世代はそれぞれの親から (ランダムに) 1つの対立遺伝子を受け継ぐべきです。
    • 各自に親を割り当てます。最も古い世代では、両方の親を NULL に設定し、より若い世代では、それぞれが異なる親を指す2つのポインタの配列にする必要があります。

create_family 関数をいくつかのTODOに分割して完成させましょう。

  • まず、新しいユーザーにメモリを割り当てる必要があります。malloc を使用してメモリーを割り当て、sizeof(person) を使用して割り当てるバイト数を取得できることを思い出してください。
  • 次に、世代数が1より大きいか (generations > 1) どうかをチェックする条件を含めます。
    • generations > 1 ならば、まだ割り当てるべき世代があることになります。create_family を再帰的に呼び出すことで、すでに parent0parent1 という 2 つの新しい親を作成しました。そして、create_family 関数は、あなたが作成した新しいpersonの親ポインタを設定する必要があります。最後に、それぞれの親からランダムに1つの対立遺伝子を選び、新しい人の両方の対立遺伝子を割り当てます。
    • そうでない場合 ( generations==1 の場合) 、この個人の親データはありません。両親は両方とも NULL に設定し、それぞれの対立遺伝子はランダムに生成します。
  • 最後に、関数は割り当てられた人のポインタを返します。

free_family 関数は、人へのポインタを入力として受け付け、その人のメモリーを解放してから、その人のすべての祖先のメモリーを再帰的に解放します。

  • これは再帰関数なので、最初にベースケースを処理する必要があります。関数への入力が NULL の場合、解放するものがないため、関数はすぐに戻ることができます。
  • そうでない場合は、子を解放する前に、その人の両方の親を再帰的に解放する必要があります。

ウォークスルー

このビデオは、コースがまだコードを書くためにCS50 IDEを使用していたときに記録されたものです。インターフェイスはあなたのCodespacesと異なるように見えますが、2つの環境の動作はほぼ同じであるはずです

ヒント

  • rand() 関数は対立遺伝子をランダムに割り当てるのに有用です。この関数は、0からRAND_MAX の整数、つまり32767を戻します。
    • 特に、0または1の擬似乱数を生成するには、式 rand() % 2を使用します。
  • 特定の人にメモリを割り当てるには、malloc(n) を使うことができます。この関数は引数としてサイズを取り、nバイトのメモリを割り当てます。
  • ポインタを介して変数にアクセスするには、矢印表記を使用できます。
    • たとえば、p が個人へのポインタである場合、この個人の最初の親へのポインタは p->parents[0]. によってアクセスできます。

解決方法がわかりませんか?

コードのテスト方法

./inheritance の実行時、プログラムは前段で説明されているルールに従う必要があります。子供は両親から1つずつ、2つの対立遺伝子をもつべきです。両親はそれぞれの両親から1つずつ、2つの対立遺伝子をもつべきです。

例えば、以下の例では、0世代の子供は世代1の両親からO対立遺伝子を受け取りました。世代1の片親は片側の祖父母からAを、もう片側の祖父母からOを受け取りました。同様に、もう片側の親は祖父母からOとBを受け取りました。

$ ./inheritance
Child (Generation 0): blood type OO
    Parent (Generation 1): blood type AO
        Grandparent (Generation 2): blood type OA
        Grandparent (Generation 2): blood type BO
    Parent (Generation 1): blood type OB
        Grandparent (Generation 2): blood type AO
        Grandparent (Generation 2): blood type BO

check50を使用して以下を実行し、コードの正確さを評価してください。ただし、コンパイルとテストは必ず自分で行ってください。

check50 cs50/labs/2022/x/inheritance

以下を実行し、style50 を使用してコードのスタイルを評価します。

style50 inheritance.c

提出方法

次のコマンドを実行し、GitHub のユーザー名とパスワードを入力してログインします。セキュリティのため、パスワードには実際の文字ではなくアスタリスク (*) が表示されます。

submit50 cs50/labs/2022/x/inheritance