C プログラミング (C Programming)

[2020/07/08, H.Aman]

[14] 構造体 演習課題

〆切は 7/17(金)14:10 です.

  • 演習 1

    サンプルプログラム③(sample3.cです.sample1.c ではありません) を別名(ex01.c)にコピーし, これを書き換えて
    以下の手順に従って 複数の有理数の合計を出力するようにしなさい.
    なお,入力の終わりは「分子が 0 の有理数」を入力した時点とする.
    【手順】(すべて main 関数内で実行)
    1. 有理数 sum を用意し,0 に初期化する(分子を 0,分母を 1 とする).
       sum.a = 0;
      sum.b = 1;
    2. 以下の i, ii, iii を無限ループ   while(1){ ... }   で繰り返す.
      1. 有理数 x を読み込む.
      2. もし   x.a == 0   ならば break; を実行して無限ループから脱出する.
      3. sum + x を改めて sum に代入する.
        有理数の足し算は関数 add を使う必要があることに注意(このまま + と書いても動きません).
    3. sum の値を出力する.

    入出力例(キーボードからの入力は赤色
     有理数の分子と分母を入力してください:1 2
     有理数の分子と分母を入力してください:3 4
     有理数の分子と分母を入力してください:5 6
     有理数の分子と分母を入力してください:7 8
     有理数の分子と分母を入力してください:0 0
     入力された有理数の合計 = 71/24
    上の入出力例は以下の結果を示している:
  • 演習 2

    まず,このプログラム(ex02.c)をダウンロードしなさい.

    これはサンプルプログラム③を以下の点で変更したものとなっている.
    ただし,関数 sub と div は未完成なので,これらを完成させなさい.
    【サンプルプログラム③からの変更点】
    • 最大公約数を求める関数 gcd において, 引数 a, b が負の場合でも対応できるよう変更(変更済み).
    • 有理数の引き算を行うための関数 sub を新しく作成(未完成).
    • 有理数の掛け算を行うための関数 mul を新しく作成(作成済み).
    • 有理数の割り算を行うための関数 div を新しく作成(未完成).
    • main 関数で,有理数の足し算以外の計算も行う(関数を呼出す)ように変更(変更済み).
    • 計算式の表示を行うための関数 print_expression を新しく作成(作成済み).

    入出力例(キーボードからの入力は赤色
     有理数 x の分子と分母を入力してください:6 8
     有理数 y の分子と分母を入力してください:8 16
     3/4 + 1/2 = 5/4
     3/4 - 1/2 = 1/4
     3/4 * 1/2 = 3/8
     3/4 / 1/2 = 3/2
  • 演習 3

    まず,このプログラム(ex03.c)をダウンロードしなさい.

    このプログラムはサンプルプログラム④ を次の点で変更したものとなっている.
    ただし,関数 print_neighbor は未完成なので,これを完成させなさい(現時点では,全員分の名前が表示されるだけになっている).
    【サンプルプログラム④からの変更点】
    • マクロ MAX を 6 に変更(変更済み).
    • プレイヤー情報をデータファイルから読み込むように変更(変更済み).
    • 近くにいるプレイヤーを表示するための関数 print_neighbor を新しく作成(未完成
    • main 関数において,print_neighbor を呼出すように変更(変更済み).
    【関数 print_neighbor の仕様】
    • 引数 a[] :全プレイヤーの情報が入った配列
    • 引数 k :注目するプレイヤーの配列内での添字
    • 機能: a[k] に該当するプレイヤーの近くにいるプレイヤーの名前を表示する(実行例を参照のこと).
      ただし,ここでいう「近くにいる」とは,両者の x 座標の差を dx として, y 座標の差を dy としたとき, dx*dx + dy*dy < 10 が成立する場合をいう.
    • 注意点: a[k] 自身(本人)を近くにいるプレイヤーとして表示してはいけません

    入出力例(キーボードからの入力は赤色
     データファイル名を入力してください:data3.txt
     データファイルから 6 人分のデータを読み込みました.
    
     aman さんの近くにいる人(たち):shiro さん;
     taro さんの近くにいる人(たち):saburo さん; goro さん;
     jiro さんの近くにいる人(たち):
     saburo さんの近くにいる人(たち):taro さん; goro さん;
     shiro さんの近くにいる人(たち):aman さん;
     goro さんの近くにいる人(たち):taro さん; saburo さん;
    (上の実行で使っている data3.txt の内容は以下の通り:ここからダウンロードしなさい)
     aman 8 8
     taro 2 3
     jiro 2 8
     saburo 3 5
     shiro 9 9
     goro 3 3
  • 演習 4

    まず,このプログラム(ex04.c)をダウンロードしなさい.

    このプログラムはサンプルプログラム④ をもとにして作った簡単なゲームになっている.
    このゲームは,以下に示す仕様のもと,迫ってくる敵(ハンター)から逃げ切ることが目的である.
    【ゲームの仕様】
    (ただし,WIDTH, HEIGHT, MAX はいずれもマクロで,順番に 3, 3, 5 と定義されている)
    • プレイヤーとハンターは,x-y 座標上のいずれかの点(ただし,x, y とも整数)に位置する.
    • プレイヤーもハンターも,動ける範囲は座標 (0,0) を左下,座標 (WIDTH-1, HEIGHT-1) を右上とした四角形の中に限定されている.
    • プレイヤーもハンターも,1 ターン毎に上下左右のいずれかの方向に 1 マスだけ移動できる.
    • プレイヤーが先手で,それに応じてハンターも動いてくる.
    • ハンターに捕まる(位置が重なる)ことなく MAX ターンが過ぎれば,プレイヤーの勝ちである.
    • もしも動けない方向へ移動しようとした場合(例えば,座標 (0,0) にいて,左に移動しようとした場合)は, そのターンは移動できずにそこに待機となる.

    このプログラムでは,プレイヤーを移動させる関数 move が未完成になっている.
    (現状では「その方向に逃げることはできません」と表示するだけで何もしていない)
    以下の仕様に従って,この関数を完成させなさい.
    なお,関数 move の中では講義で説明した 「p->x」という書き方を用いること.
    【関数 move の仕様】
    • 引数 p :プレイヤーの情報が入った構造体へのポインタ
    • 引数 dx, dy :プレイヤーを移動させる量
    • 機能: ポインタ p が参照しているプレイヤー(構造体)の x, y 座標を更新する.
      更新する量は dx, dy であり,それぞれ x 座標を dx だけ, y 座標を dy だけ増やす. (なお,dx, dy は負の場合もある)
    • 注意点: 移動できる範囲には制限があるので,移動できない場合は 「その方向には逃げることができません」 とだけ表示して,実際は移動させない.

    入出力例(キーボードからの入力は赤色
    [Y] はあなた,[H] はハンターの位置を表している.
     あなたの名前を入力してください:aman
      aman : (0,0)
      hunter : (2,2)
      + --- + ---[H]
      |     |     |
      |     |     |
      + --- + --- +
      |     |     |
      |     |     |
     [Y]--- + --- +
     
     [1 回目]
     どの方向に逃げますか?(1:上,2:右,3:下,4:左)
     > 1
      aman : (0,1)
      hunter : (1,2)
      + ---[H]--- +
      |     |     |
      |     |     |
     [Y]--- + --- +
      |     |     |
      |     |     |
      + --- + --- +
    
     [2 回目]
     どの方向に逃げますか?(1:上,2:右,3:下,4:左)
     > 3
      aman : (0,0)
      hunter : (1,1)
      + --- + --- +
      |     |     |
      |     |     |
      + ---[H]--- +
      |     |     |
      |     |     |
     [Y]--- + --- +
    
     [3 回目]
     どの方向に逃げますか?(1:上,2:右,3:下,4:左)
     > 2
      aman : (1,0)
      hunter : (1,0)
      + --- + --- +
      |     |     |
      |     |     |
      + --- + --- +
      |     |     |
      |     |     |
      + ---(X)--- +
    
     aman は捕まってしまいました... GAME OVER
    (※ 実は,1 回だけわざと逃げることのできない方向を選んで,1 手だけ無駄にするとクリアできます.)

余裕のある人は

  • 演習 2【発展課題】

    演習 2 で作ったプログラムを別名(ex02e.c)にコピーし,次のように改良しなさい:
    分子または分母に負の数が含まれてもよいように,関数 reduce を改良しなさい.
    つまり,関数 reduce を使って約分する際に, 有理数として負になる場合は必ず分子の値を負にして,分母は常に正となるようにしなさい.
    (例)「5/-10」→ 「-1/2」
    (例) 「-15/-10」→ 「3/2」

    入出力例(キーボードからの入力は赤色
     有理数 x の分子と分母を入力してください:2 -3
     有理数 y の分子と分母を入力してください:-10 -4
     -2/3 + 5/2 = 11/6
     -2/3 - 5/2 = -19/6
     -2/3 * 5/2 = -5/3
     -2/3 / 5/2 = -4/15
  • 演習 3【発展課題】

    演習 3 で作ったプログラムを別名(ex03e.c)にコピーし,次のように変更しなさい:
    最も遠い人の名前だけを表示しなさい(与えられるデータでは,一番遠い人が 1 人に決まると仮定してよい).
    距離は dx*dx + dy*dy で求まるのでこれを使うこと(正しくは距離の 2 乗だが,最も遠い人を決定するだけならこれを使っても支障はない).

    入出力例(キーボードからの入力は赤色
     データファイル名を入力してください:data3.txt
     データファイルから 6 人分のデータを読み込みました.
    
     aman さんから最も遠くにいる人:taro さん
     taro さんから最も遠くにいる人:shiro さん
     jiro さんから最も遠くにいる人:shiro さん
     saburo さんから最も遠くにいる人:shiro さん
     shiro さんから最も遠くにいる人:taro さん
     goro さんから最も遠くにいる人:shiro さん