演習問題の大半は CUI プログラム(コマンドプロンプト)での作成を前提としていますが、 問題の一部を、GUI プログラム(ウィンドウアプリ)で作成するための雛形を用意しました。
「C#の簡単なプログラム例」 中のプログラムを実際に作成し、コンパイル・実行してみよ。
Console.Write を用いて、自分の名前を画面に表示せよ。
using System; class Sample { static void Main() { Console.Write("岩永信之"); } }
Console.ReadLine を用いて文字列を1行読み込み、 Console.Write を用いて読んだ文字列をそのまま鸚鵡返しするプログラムを作成せよ。
おまけ: 1度読み込んだ文字列を2度ずつ鸚鵡返しするものを作成せよ。
using System; class Sample { static void Main() { string line = Console.ReadLine(); Console.Write(line); } }
using System; class Sample { static void Main() { string line = Console.ReadLine(); Console.Write(line); Console.Write(line); } }
2つの整数を入力し、 その整数の四則演算(+, -, ×, ÷)結果を表示するプログラムを作成せよ。
using System; class Exercise { static void Main() { Console.Write("input a: "); int a = int.Parse(Console.ReadLine()); Console.Write("input b: "); int b = int.Parse(Console.ReadLine()); Console.Write("{0} + {1} = {2}\n", a, b, a + b); Console.Write("{0} - {1} = {2}\n", a, b, a - b); Console.Write("{0} * {1} = {2}\n", a, b, a * b); Console.Write("{0} / {1} = {2}\n", a, b, a / b); } }
前問の「整数の四則演算」の、 double, short 等の他の型を用いた物を作成せよ。
例として double 版を掲載。
using System; class Exercise { static void Main() { Console.Write("input a: "); double a = double.Parse(Console.ReadLine()); Console.Write("input b: "); double b = double.Parse(Console.ReadLine()); Console.Write("{0} + {1} = {2}\n", a, b, a + b); Console.Write("{0} - {1} = {2}\n", a, b, a - b); Console.Write("{0} * {1} = {2}\n", a, b, a * b); Console.Write("{0} / {1} = {2}\n", a, b, a / b); } }
複素数 x + iy の逆数を求めるプログラムを作成せよ。
using System; class Exercise { static void Main() { Console.Write("実部を入力してください: "); double x = double.Parse(Console.ReadLine()); Console.Write("虚部を入力してください: "); double y = double.Parse(Console.ReadLine()); double norm = x * x + y * y; Console.Write("{0} + i({1}) の逆数は {2} + i({3})\n)", x, y, x / norm, -y / norm); } }
半径を入力し、その半径の円の面積を求めるプログラムを作成せよ。
using System; class Exercise { static void Main() { double r; // 半径 Console.Write("半径を入力してください: "); r = double.Parse(Console.ReadLine()); double area = r * r * 3.1415926535897932; Console.Write("面積 = {0}\n", area); } }
体重と身長を入力し、BMIを求めるプログラムを作成せよ。
BMIは、WHO(世界保健機関)が推奨しているもので、Body Mass Indexの略称で、肥満度指数とも呼ばれています。 BMIは肥満度の基準として、広く使用されている測定方法です。 計算式は、下記のとおりで比較的簡単に計算できることも特徴です。
BMI = 体重(kg)÷{身長(m)×身長(m)}
BMIの値が22のときに病気になる可能性が最も低く、BMIが26を超えると糖尿病など生活習慣病になるリスクが高まると言われています。
BMI 値 19.8未満 やせ型 19.8~24.2未満 普通 24.2~26.4未満 やや肥満(過体重) 26.4~35.0未満 肥満 35.0以上 高度肥満(要治療)
以下にプログラムの実行結果の例を示す。
身長[cm] = 175.5 体重[kg] = 52.4 BMI = 17.0128489216808
using System; class Exercise { static void Main() { double height; // 身長[cm] double weight; // 体重[kg] Console.Write("身長[cm]: "); height = double.Parse(Console.ReadLine()); height *= 0.01; // cm → m Console.Write("体重[kg]: "); weight = double.Parse(Console.ReadLine()); double bmi = weight / (height * height); Console.Write("BMI = {0}\n", bmi); } }
適当な文字を入力し、その文字コードを表示するプログラムを作成せよ。 (char 型の変数を int 型にキャストすると文字コードが得られます。)
using System; class Exercise { static void Main() { char c; Console.Write("文字を入力してください: "); c = Console.ReadLine()[0]; Console.Write("文字 {0} の文字コードは {1}\n", c, (int)c); } }
整数型(int, short, long)同士の割り算では、結果も整数となり、あまりは切り捨てられます。 切り捨てられると困る場合、浮動小数点数(double, float)にキャストしてから計算する必要があります。
このことを確かめるため、 2つの整数を入力し、 整数のままで割り算した結果(あまり切り捨て)と、 浮動小数点数として割り算した結果を比較するプログラムを作成せよ。
using System; class Exercise { static void Main() { Console.Write("input a: "); int a = int.Parse(Console.ReadLine()); Console.Write("input b: "); int b = int.Parse(Console.ReadLine()); Console.Write("整数: {0} / {1} = {2} … {3}\n", a, b, a / b, a % b); Console.Write("実数: {0} / {1} = {2}\n", a, b, a / (double)b); } }
double → int にキャストすると、値が整数に切り詰められます。 このとき、どのようにして値が切り詰められるのか(切捨てなのか切り上げなのか等)を調べよ。 (正の数だけでなく、負の数も。)
using System; class Exercise { static void Main() { // まず、正の数をいくつか確認。 Console.Write("{0} → {1}\n", 3.8, (int)3.8); Console.Write("{0} → {1}\n", 3.1, (int)3.1); Console.Write("{0} → {1}\n", 2.7, (int)2.7); Console.Write("{0} → {1}\n", 2.4, (int)2.4); Console.Write("{0} → {1}\n", 1.5, (int)1.5); Console.Write("{0} → {1}\n", 0.5, (int)0.5); // 負の数も。 Console.Write("{0} → {1}\n", -3.8, (int)-3.8); Console.Write("{0} → {1}\n", -3.1, (int)-3.1); Console.Write("{0} → {1}\n", -2.7, (int)-2.7); Console.Write("{0} → {1}\n", -2.4, (int)-2.4); Console.Write("{0} → {1}\n", -1.5, (int)-1.5); Console.Write("{0} → {1}\n", -0.5, (int)-0.5); } }
3.8 → 3 3.1 → 3 2.7 → 2 2.4 → 2 1.5 → 1 0.5 → 0 -3.8 → -3 -3.1 → -3 -2.7 → -2 -2.4 → -2 -1.5 → -1 -0.5 → 0
結果を見ての通り、正の数は切り捨て、負の数は切り上げ(0 に向かって丸め)になります。
正負問わず値を切り捨てたい場合は Math.Floor
関数を、
切り上げたい場合は Math.Ceiling
関数を、
四捨五入したい場合は Math.Round
関数を使用します。
ユーザから入力された整数が奇数か偶数か判定するプログラムを作成せよ。
using System; class Exercise { static void Main() { Console.Write("整数を入力してください: "); int n = int.Parse(Console.ReadLine()); if (n % 2 == 0) Console.Write("{0} は偶数です\n", n); else Console.Write("{0} は奇数です\n", n); } }
組込み演算子の問題 5のプログラムを修正し、 BMI 値から体型(やせ型、普通、やや肥満、肥満、高度肥満)を判定し、 表示するプログラムを作成せよ。
using System; class Exercise { static void Main() { Console.Write("身長[cm]: "); double height = double.Parse(Console.ReadLine()) * 0.01; Console.Write("体重[kg]: "); double weight = double.Parse(Console.ReadLine()); double bmi = weight / (height * height); Console.Write("BMI = {0}\n", bmi); if(bmi < 19.8) Console.Write("やせ型"); else if(bmi < 24.2) Console.Write("普通"); else if(bmi < 26.4) Console.Write("やや肥満(過体重)"); else if(bmi < 35.0) Console.Write("肥満"); else Console.Write("高度肥満(要治療)"); Console.Write("です\n"); } }
switch 文を使って150以下の平方数(4=2×2、9=3×3、16=4×4というように、ある整数の二乗になっている数)を判別するプログラムを作成せよ。 ユーザに整数値を1つ入力してもらい、 判別結果を出力するものとする。
ヒント: 要するに、ユーザからの入力が 1, 4, 9, 16, ・・・になっているかどうかを switch 文で判別します。
using System; class Exercise { static void Main() { Console.Write("整数を入力してください: "); int n = int.Parse(Console.ReadLine()); switch (n) { case 1: Console.Write("{0} は平方数です。\n", n); break; case 2 * 2: goto case 1; case 3 * 3: goto case 1; case 4 * 4: goto case 1; case 5 * 5: goto case 1; case 6 * 6: goto case 1; case 7 * 7: goto case 1; case 8 * 8: goto case 1; case 9 * 9: goto case 1; case 10 * 10: goto case 1; case 11 * 11: goto case 1; case 12 * 12: goto case 1; default: Console.Write("{0} は平方数ではないか、150以上です\n", n); break; } } }
数値を3つ入力してもらい、 その3つの値の中の最大値、最小値を求めるプログラムを作成せよ。
単純な条件分岐による方法。
using System; class Exercise { static void Main() { Console.Write("値1: "); double x = double.Parse(Console.ReadLine()); Console.Write("値2: "); double y = double.Parse(Console.ReadLine()); Console.Write("値3: "); double z = double.Parse(Console.ReadLine()); if (x > y) { if (x > z) { if (y > z) Console.Write("最大 {0}, 中間 {1}, 最小 {2}\n", x, y, z); else Console.Write("最大 {0}, 中間 {1}, 最小 {2}\n", x, z, y); } else Console.Write("最大 {0}, 中間 {1}, 最小 {2}\n", z, x, y); } else { if (y > z) { if (x > z) Console.Write("最大 {0}, 中間 {1}, 最小 {2}\n", y, x, z); else Console.Write("最大 {0}, 中間 {1}, 最小 {2}\n", y, z, x); } else Console.Write("最大 {0}, 中間 {1}, 最小 {2}\n", z, y, x); } } }
3つの数値をあらかじめ整列してしまう方法。
using System; class Exercise { static void Main() { Console.Write("値1: "); double x = double.Parse(Console.ReadLine()); Console.Write("値2: "); double y = double.Parse(Console.ReadLine()); Console.Write("値3: "); double z = double.Parse(Console.ReadLine()); double tmp; if (y < z) { tmp = y; y = z; z = tmp; } if (x < y) { tmp = x; x = y; y = tmp; } if (y < z) { tmp = y; y = z; z = tmp; } Console.Write("最大 {0}, 中間{1}, 最小 {2}\n", x, y, z); } }
ユーザに整数 n を入力してもらい、
1 から n までの整数の和を求めるプログラムを作成せよ。
ただし、
ループを使って和を求めたものと、
和の公式
n (n + 1)
の結果を比較せよ。
1 2
using System; class Exercise { static void Main() { Console.Write("n: "); int n = int.Parse(Console.ReadLine()); int sum = 0; for (int i = 1; i <= n; ++i) { sum += i; } Console.Write("loop {0}, formula {1}\n", sum, n * (n + 1) / 2); } }
平方数(4=2×2、9=3×3、16=4×4というように、ある整数の二乗になっている数)を判別するプログラムを作成せよ。 ユーザに整数値を1つ入力してもらい、 判別結果を出力するものとする。 条件分岐の問題 2と異なり、判別できる数値に上限は設けない。
ヒント:ループと条件分岐を組み合わせて作る。
using System; class Exercise { static void Main() { Console.Write("整数を入力してください: "); int n = int.Parse(Console.ReadLine()); int i; for (i = 0; i <= n; ++i) { if (n == i * i) break; } if (i <= n) Console.Write("{0} = {1} × {1} は平方数です\n", n, i); else Console.Write("{0} は平方数ではありません\n", n); } }
ちなみに、この for ループの継続条件の部分は、
i <= (int)Math.Sqrt(n)
でも OK。
(その下の if 文の条件も変更する必要あり。)
Sqrt は n の平方根を求める関数。
2重ループを使って掛け算の九九表を表示するプログラムを作成せよ。
using System; class Exercise { static void Main() { for (int i = 1; i <= 9; ++i) { for (int j = 1; j <= 9; ++j) { Console.Write("{0,3}", i * j); } Console.Write('\n'); } } }
for 文を使って以下の漸化式の一般項 an を20項目まで求めるプログラムを作成せよ。 ( an を配列で表す。)
using System; class Exercise { static void Main() { int[] a = new int[21]; a[0] = 3; a[1] = 1; // 数列を求める。 for (int i = 2; i < a.Length; ++i) { a[i] = 2 * a[i - 1] - 2 * a[i - 2]; } // 求めた数列を表示。 for (int i = 0; i < a.Length; ++i) { Console.Write("{0} ", a[i]); } Console.Write('\n'); } }
int 型の配列に格納されている値の最大値、最小値および平均値を求めよ。 できれば、配列の長さ n および n 個の整数値をユーザに入力してもらうようにすること。
using System; class Exercise { static void Main() { // 配列長の入力 Console.Write("配列の長さ: "); int n = int.Parse(Console.ReadLine()); // 配列の値の入力 int[] a = new int[n]; for (int i = 0; i < n; ++i) { Console.Write("{0}: ", i); a[i] = int.Parse(Console.ReadLine()); } // 最大値、最小値、平均値の計算 int max = int.MinValue; int min = int.MaxValue; double average = 0; for (int i = 0; i < n; ++i) { if (max < a[i]) max = a[i]; if (min > a[i]) min = a[i]; average += a[i]; } average /= n; Console.Write( @" 最大値: {0} 最小値: {1} 平均値: {2} " , max, min, average); } }
double 型の2次元配列を行列に見立てて、行列の掛け算を行うプログラムを作成せよ。
行列の次元は任意だけども、例として2×2行列の場合を示す。
using System; class Exercise { static void Main() { double[,] a = new double[,] { {1, 1}, {1, 0}, }; double[,] b = new double[,] { {1, 2}, {3, 4}, }; // ここより下は、a, b のサイズが任意の場合でも正しく動作する。 double[,] c = new double[a.GetLength(0), b.GetLength(1)]; // a×b を計算 for (int i = 0; i < a.GetLength(0); ++i) for (int j = 0; j < b.GetLength(1); ++j) for (int k = 0; k < a.GetLength(1); ++k) c[i, j] += a[i, k] * b[k, j]; // a を表示 Console.Write("a =\n"); for (int i = 0; i < a.GetLength(0); ++i) { for (int j = 0; j < a.GetLength(1); ++j) Console.Write("{0, 4} ", a[i, j]); Console.Write('\n'); } // b を表示 Console.Write("b =\n"); for (int i = 0; i < b.GetLength(0); ++i) { for (int j = 0; j < b.GetLength(1); ++j) Console.Write("{0, 4} ", b[i, j]); Console.Write('\n'); } // a×b を表示 Console.Write("a×b =\n"); for (int i = 0; i < c.GetLength(0); ++i) { for (int j = 0; j < c.GetLength(1); ++j) Console.Write("{0, 4} ", c[i, j]); Console.Write('\n'); } } }
int 型の配列に格納されている値の最大値、最小値および平均値を求める関数をそれぞれ作成せよ。
/// <summary> /// 配列中の値の最大値を求める。 /// </summary> /// <param name="a">対象の配列</param> /// <returns>最大値</returns> static int Max(int[] a) /// <summary> /// 配列中の値の最小値を求める。 /// </summary> /// <param name="a">対象の配列</param> /// <returns>最小値</returns> static int Min(int[] a) /// <summary> /// 配列中の値の平均値を求める。 /// </summary> /// <param name="a">対象の配列</param> /// <returns>平均値</returns> static double Average(int[] a)
using System; class Exercise { static void Main() { // 配列長の入力 Console.Write("配列の長さ: "); int n = int.Parse(Console.ReadLine()); // 配列の値の入力 int[] a = new int[n]; for (int i = 0; i < n; ++i) { Console.Write("{0}: ", i); a[i] = int.Parse(Console.ReadLine()); } Console.Write( @" 最大値: {0} 最小値: {1} 平均値: {2} " , Max(a), Min(a), Average(a)); } /// <summary> /// 配列中の値の最大値を求める。 /// </summary> /// <param name="a">対象の配列</param> /// <returns>最大値</returns> static int Max(int[] a) { int max = int.MinValue; for (int i = 0; i < a.Length; ++i) { if (max < a[i]) max = a[i]; } return max; } /// <summary> /// 配列中の値の最小値を求める。 /// </summary> /// <param name="a">対象の配列</param> /// <returns>最小値</returns> static int Min(int[] a) { int min = int.MaxValue; for (int i = 0; i < a.Length; ++i) { if (min > a[i]) min = a[i]; } return min; } /// <summary> /// 配列中の値の最大値を求める。 /// </summary> /// <param name="a">対象の配列</param> /// <returns>平均値</returns> static double Average(int[] a) { double average = 0; for (int i = 0; i < a.Length; ++i) { average += a[i]; } return average / a.Length; } }
double 型の値 x の整数冪を求める関数 Power を作成せよ。
/// <summary> /// x の整数冪を求める。 /// </summary> /// <param name="x">仮数 x</param> /// <param name="n">指数 n</param> /// <returns>x の n 乗</returns> static double Power( double x, int n)
using System; class Exercise { static void Main() { const double x = 3; Console.Write("{0}\n", Power(x, 4)); Console.Write("{0}\n", Power(x, -1)); Console.Write("{0}\n", Power(x, -2)); Console.Write("{0}\n", Power(x, 0)); } /// <summary> /// x の整数冪を求める。 /// </summary> /// <param name="x">仮数 x</param> /// <param name="n">指数 n</param> /// <returns>x の n 乗</returns> static double Power( double x, int n) { if (n == 0) return 1; if (n < 0) { x = 1.0 / x; n = -n; } double y = x; while (--n > 0) { y *= x; } return y; } }
配列に格納されている値の最大値を求める関数を、
int[]
に対するものと
double[]
に対するものの2種類作成せよ。
using System; class Exercise { static void Main() { int[] ai = new int[] { 1, 3, 9, 2, 5, 6, 4 }; double[] ad = new double[] { 1, 3, 9, 2, 5, 6, 4 }; Console.Write("{0}, {1}\n", Max(ai), Max(ad)); } /// <summary> /// 配列中の値の最大値を求める。 /// </summary> /// <param name="a">対象の配列</param> /// <returns>最大値</returns> static int Max(int[] a) { int max = int.MinValue; for (int i = 0; i < a.Length; ++i) { if (max < a[i]) max = a[i]; } return max; } /// <summary> /// 配列中の値の最大値を求める。 /// </summary> /// <param name="a">対象の配列</param> /// <returns>最大値</returns> static double Max(double[] a) { double max = int.MinValue; for (int i = 0; i < a.Length; ++i) { if (max < a[i]) max = a[i]; } return max; } }
見ての通り、型が変わっただけで、処理自体は全く同じものになっています。 このように、型と無関係に同じ処理で実現できるものは、 ジェネリックスを使うことで実装の手間を軽減できます。
サンプル中の Point 構造体を使って、三角形を表す構造体 Triangle
を作成せよ。
(3つの頂点を a, b, c 等のメンバー変数として持つ。)
また、作成した構造体に、三角形の面積を求めるメンバー関数 GetArea
を追加せよ。
/// <summary> /// 三角形の面積を求める。 /// </summary> /// <returns>面積</returns> public double GetArea()
using System; /// <summary> /// 2次元の点をあらわす構造体 /// </summary> struct Point { public double x; // x 座標 public double y; // y 座標 public override string ToString() { return "(" + x + ", " + y + ")"; } } /// <summary> /// 2次元空間上の三角形をあらわす構造体 /// </summary> struct Triangle { public Point a; public Point b; public Point c; /// <summary> /// 三角形の面積を求める。 /// </summary> /// <returns>面積</returns> public double GetArea() { double abx, aby, acx, acy; abx = b.x - a.x; aby = b.y - a.y; acx = c.x - a.x; acy = c.y - a.y; return 0.5 * Math.Abs(abx * acy - acx * aby); } } class Test { static void Main() { Triangle t; t.a.x = 0; t.a.y = 0; t.b.x = 3; t.b.y = 4; t.c.x = 4; t.c.y = 3; Console.Write("{0}\n", t.GetArea()); } }
「構造体」
の構造体の問題 1で作成した Triangle
構造体をクラスで作り直せ。
(Point
構造体は構造体のままで OK。)
注1:現時点では、 単に struct が class に変わるだけで、特にメリットはありませんが、 今後、 「継承」 」や 「多態性」 を通して、 クラスのメリットを徐々に加えていく予定です。
注2: クラスにした場合、メンバー変数をきちんと初期化してやらないと正しく動作しません。 (構造体でもメンバー変数の初期化はきちんとする方がいいんですが。) 初期化に関しては、次節の 「コンストラクターとデストラクター」 で説明します。
前節クラスの問題 1の Point
構造体および Triangle
クラスに、
以下のようなコンストラクターを追加せよ。
/// <summary> /// 座標値 (x, y) を与えて初期化。 /// </summary> /// <param name="x">x 座標値</param> /// <param name="y">y 座標値</param> public Point(double x, double y)
/// <summary> /// 3つの頂点の座標を与えて初期化。 /// </summary> /// <param name="a">頂点A</param> /// <param name="b">頂点B</param> /// <param name="c">頂点C</param> public Triangle(Point a, Point b, Point c)
using System; /// <summary> /// 2次元の点をあらわす構造体 /// </summary> struct Point { public double x; // x 座標 public double y; // y 座標 /// <summary> /// 座標値 (x, y) を与えて初期化。 /// </summary> /// <param name="x">x 座標値</param> /// <param name="y">y 座標値</param> public Point(double x, double y) { this.x = x; this.y = y; } public override string ToString() { return "(" + x + ", " + y + ")"; } } /// <summary> /// 2次元空間上の三角形をあらわす構造体 /// </summary> class Triangle { public Point a; public Point b; public Point c; /// <summary> /// 3つの頂点の座標を与えて初期化。 /// </summary> /// <param name="a">頂点A</param> /// <param name="b">頂点B</param> /// <param name="c">頂点C</param> public Triangle(Point a, Point b, Point c) { this.a = a; this.b = b; this.c = c; } /// <summary> /// 三角形の面積を求める。 /// </summary> /// <returns>面積</returns> public double GetArea() { double abx, aby, acx, acy; abx = b.x - a.x; aby = b.y - a.y; acx = c.x - a.x; acy = c.y - a.y; return 0.5 * Math.Abs(abx * acy - acx * aby); } } /// <summary> /// Class1 の概要の説明です。 /// </summary> class Class1 { static void Main() { Triangle t = new Triangle( new Point(0, 0), new Point(3, 4), new Point(4, 3)); Console.Write("{0}\n", t.GetArea()); } }
クラスの問題 1の Point
構造体および Triangle
クラスの各メンバー変数に対して、
プロパティを使って実装の隠蔽を行え。
using System; /// <summary> /// 2次元の点をあらわす構造体 /// </summary> struct Point { double x; // x 座標 double y; // y 座標 #region 初期化 /// <summary> /// 座標値 (x, y) を与えて初期化。 /// </summary> /// <param name="x">x 座標値</param> /// <param name="y">y 座標値</param> public Point(double x, double y) { this.x = x; this.y = y; } #endregion #region プロパティ /// <summary> /// x 座標。 /// </summary> public double X { get { return this.x; } set { this.x = value; } } /// <summary> /// y 座標。 /// </summary> public double Y { get { return this.y; } set { this.y = value; } } #endregion public override string ToString() { return "(" + x + ", " + y + ")"; } } /// <summary> /// 2次元空間上の三角形をあらわす構造体 /// </summary> class Triangle { Point a; Point b; Point c; #region 初期化 /// <summary> /// 3つの頂点の座標を与えて初期化。 /// </summary> /// <param name="a">頂点A</param> /// <param name="b">頂点B</param> /// <param name="c">頂点C</param> public Triangle(Point a, Point b, Point c) { this.a = a; this.b = b; this.c = c; } #endregion #region プロパティ /// <summary> /// 頂点A。 /// </summary> public Point A { get { return a; } set { a = value; } } /// <summary> /// 頂点B。 /// </summary> public Point B { get { return b; } set { b = value; } } /// <summary> /// 頂点C。 /// </summary> public Point C { get { return c; } set { c = value; } } #endregion /// <summary> /// 三角形の面積を求める。 /// </summary> /// <returns>面積</returns> public double GetArea() { double abx, aby, acx, acy; abx = b.X - a.X; aby = b.Y - a.Y; acx = c.X - a.X; acy = c.Y - a.Y; return 0.5 * Math.Abs(abx * acy - acx * aby); } } /// <summary> /// Class1 の概要の説明です。 /// </summary> class Class1 { static void Main() { Triangle t = new Triangle( new Point(0, 0), new Point(3, 4), new Point(4, 3)); Console.Write("{0}\n", t.GetArea()); } }
クラスの問題 1の Point
構造体に、
2点間の距離を求める static メソッド GetDistance
を追加せよ。
/// <summary> /// A-B 間の距離を求める。 /// </summary> /// <param name="a">点A</param> /// <param name="b">点B</param> /// <returns>距離AB</returns> public static double GetDistance(Point a, Point b)
また、GetDistance
を用いて、
Triangle
クラスに三角形の周を求めるメソッド
GetPerimeter
を追加せよ。
/// <summary> /// 三角形の周の長さを求める。 /// </summary> /// <returns>周</returns> public double GetPerimeter()
using System; /// <summary> /// 2次元の点をあらわす構造体 /// </summary> struct Point { double x; // x 座標 double y; // y 座標 #region 初期化 /// <summary> /// 座標値 (x, y) を与えて初期化。 /// </summary> /// <param name="x">x 座標値</param> /// <param name="y">y 座標値</param> public Point(double x, double y) { this.x = x; this.y = y; } #endregion #region プロパティ /// <summary> /// x 座標。 /// </summary> public double X { get { return this.x; } set { this.x = value; } } /// <summary> /// y 座標。 /// </summary> public double Y { get { return this.y; } set { this.y = value; } } #endregion /// <summary> /// A-B 間の距離を求める。 /// </summary> /// <param name="a">点A</param> /// <param name="b">点B</param> /// <returns>距離AB</returns> public static double GetDistance(Point a, Point b) { double x = a.x - b.x; double y = a.y - b.y; return Math.Sqrt(x * x + y * y); } public override string ToString() { return "(" + x + ", " + y + ")"; } } /// <summary> /// 2次元空間上の三角形をあらわす構造体 /// </summary> class Triangle { Point a; Point b; Point c; #region 初期化 /// <summary> /// 3つの頂点の座標を与えて初期化。 /// </summary> /// <param name="a">頂点A</param> /// <param name="b">頂点B</param> /// <param name="c">頂点C</param> public Triangle(Point a, Point b, Point c) { this.a = a; this.b = b; this.c = c; } #endregion #region プロパティ /// <summary> /// 頂点A。 /// </summary> public Point A { get { return a; } set { a = value; } } /// <summary> /// 頂点B。 /// </summary> public Point B { get { return b; } set { b = value; } } /// <summary> /// 頂点C。 /// </summary> public Point C { get { return c; } set { c = value; } } #endregion /// <summary> /// 三角形の面積を求める。 /// </summary> /// <returns>面積</returns> public double GetArea() { double abx, aby, acx, acy; abx = b.X - a.X; aby = b.Y - a.Y; acx = c.X - a.X; acy = c.Y - a.Y; return 0.5 * Math.Abs(abx * acy - acx * aby); } /// <summary> /// 三角形の周の長さを求める。 /// </summary> /// <returns>周</returns> public double GetPerimeter() { double l = Point.GetDistance(this.a, this.b); l += Point.GetDistance(this.a, this.c); l += Point.GetDistance(this.b, this.c); return l; } } /// <summary> /// Class1 の概要の説明です。 /// </summary> class Class1 { static void Main() { Triangle t = new Triangle( new Point(0, 0), new Point(3, 4), new Point(4, 3)); Console.Write("{0}\n", t.GetArea()); Console.Write("{0}\n", t.GetPerimeter()); } }
クラスの問題 1の Point
構造体を2次元ベクトルとみなして、
ベクトルの和・差を計算する演算子 +
および -
を追加せよ。
/// <summary> /// ベクトル和 /// </summary> /// <param name="a">点A</param> /// <param name="b">点B</param> /// <returns>和</returns> public static Point operator +(Point a, Point b) /// <summary> /// ベクトル差 /// </summary> /// <param name="a">点A</param> /// <param name="b">点B</param> /// <returns>和</returns> public static Point operator -(Point a, Point b)
using System; /// <summary> /// 2次元の点をあらわす構造体 /// </summary> struct Point { double x; // x 座標 double y; // y 座標 #region 初期化 /// <summary> /// 座標値 (x, y) を与えて初期化。 /// </summary> /// <param name="x">x 座標値</param> /// <param name="y">y 座標値</param> public Point(double x, double y) { this.x = x; this.y = y; } #endregion #region プロパティ /// <summary> /// x 座標。 /// </summary> public double X { get { return this.x; } set { this.x = value; } } /// <summary> /// y 座標。 /// </summary> public double Y { get { return this.y; } set { this.y = value; } } #endregion #region 演算子 /// <summary> /// ベクトル和 /// </summary> /// <param name="a">点A</param> /// <param name="b">点B</param> /// <returns>和</returns> public static Point operator +(Point a, Point b) { return new Point(a.x + b.x, a.y + b.y); } /// <summary> /// ベクトル差 /// </summary> /// <param name="a">点A</param> /// <param name="b">点B</param> /// <returns>和</returns> public static Point operator -(Point a, Point b) { return new Point(a.x - b.x, a.y - b.y); } #endregion /// <summary> /// A-B 間の距離を求める。 /// </summary> /// <param name="a">点A</param> /// <param name="b">点B</param> /// <returns>距離AB</returns> public static double GetDistance(Point a, Point b) { double x = a.x - b.x; double y = a.y - b.y; return Math.Sqrt(x * x + y * y); } public override string ToString() { return "(" + x + ", " + y + ")"; } } /// <summary> /// 2次元空間上の三角形をあらわす構造体 /// </summary> class Triangle { Point a; Point b; Point c; #region 初期化 /// <summary> /// 3つの頂点の座標を与えて初期化。 /// </summary> /// <param name="a">頂点A</param> /// <param name="b">頂点B</param> /// <param name="c">頂点C</param> public Triangle(Point a, Point b, Point c) { this.a = a; this.b = b; this.c = c; } #endregion #region プロパティ /// <summary> /// 頂点A。 /// </summary> public Point A { get { return a; } set { a = value; } } /// <summary> /// 頂点B。 /// </summary> public Point B { get { return b; } set { b = value; } } /// <summary> /// 頂点C。 /// </summary> public Point C { get { return c; } set { c = value; } } #endregion /// <summary> /// 三角形の面積を求める。 /// </summary> /// <returns>面積</returns> public double GetArea() { Point ab = b - a; Point ac = c - a; return 0.5 * Math.Abs(ab.X * ac.Y - ac.X * ab.Y); } /// <summary> /// 三角形の周の長さを求める。 /// </summary> /// <returns>周</returns> public double GetPerimeter() { double l = Point.GetDistance(this.a, this.b); l += Point.GetDistance(this.a, this.c); l += Point.GetDistance(this.b, this.c); return l; } } /// <summary> /// Class1 の概要の説明です。 /// </summary> class Class1 { static void Main() { Triangle t = new Triangle( new Point(0, 0), new Point(3, 4), new Point(4, 3)); Console.Write("{0}\n", t.GetArea()); Console.Write("{0}\n", t.GetPerimeter()); } }
クラスの問題 1の Triangle
クラスを元に、
以下のような継承構造を持つクラスを作成せよ。
まず、三角形や円等の共通の基底クラスとなる Shape
クラスを以下のように作成。
/// <summary> /// 2次元空間上の図形を表すクラス。 /// 三角形や円等の共通の基底クラス。 /// </summary> class Shape { virtual public double GetArea() { return 0; } virtual public double GetPerimeter() { return 0; } }
そして、Shape
クラスを継承して、
三角形 Triangle
クラスと
円 Circle
クラスを作成。
/// <summary> /// 2次元空間上の三角形をあらわすクラス /// </summary> class Triangle : Shape
/// <summary> /// 2次元空間上の円をあらわすクラス /// </summary> class Circle : Shape
using System; /// <summary> /// 2次元の点をあらわす構造体 /// </summary> struct Point { double x; // x 座標 double y; // y 座標 #region 初期化 /// <summary> /// 座標値 (x, y) を与えて初期化。 /// </summary> /// <param name="x">x 座標値</param> /// <param name="y">y 座標値</param> public Point(double x, double y) { this.x = x; this.y = y; } #endregion #region プロパティ /// <summary> /// x 座標。 /// </summary> public double X { get { return this.x; } set { this.x = value; } } /// <summary> /// y 座標。 /// </summary> public double Y { get { return this.y; } set { this.y = value; } } #endregion #region 演算子 /// <summary> /// ベクトル和 /// </summary> /// <param name="a">点A</param> /// <param name="b">点B</param> /// <returns>和</returns> public static Point operator +(Point a, Point b) { return new Point(a.x + b.x, a.y + b.y); } /// <summary> /// ベクトル差 /// </summary> /// <param name="a">点A</param> /// <param name="b">点B</param> /// <returns>和</returns> public static Point operator -(Point a, Point b) { return new Point(a.x - b.x, a.y - b.y); } #endregion /// <summary> /// A-B 間の距離を求める。 /// </summary> /// <param name="a">点A</param> /// <param name="b">点B</param> /// <returns>距離AB</returns> public static double GetDistance(Point a, Point b) { double x = a.x - b.x; double y = a.y - b.y; return Math.Sqrt(x * x + y * y); } public override string ToString() { return "(" + x + ", " + y + ")"; } } /// <summary> /// 2次元空間上の図形を表すクラス。 /// 三角形や円等の共通の基底クラス。 /// </summary> class Shape { virtual public double GetArea() { return 0; } virtual public double GetPerimeter() { return 0; } } /// <summary> /// 2次元空間上の円をあらわすクラス /// </summary> class Circle : Shape { Point center; double radius; #region 初期化 /// <summary> /// 半径を指定して初期化。 /// </summary> /// <param name="r">半径。</param> public Circle(Point center, double r) { this.center = center; this.radius = r; } #endregion #region プロパティ /// <summary> /// 円の中心。 /// </summary> public Point Center { get { return this.center; } set { this.center = value; } } /// <summary> /// 円の半径。 /// </summary> public double Radius { get { return this.radius; } set { this.radius = value; } } #endregion #region 面積・周 /// <summary> /// 円の面積を求める。 /// </summary> /// <returns>面積</returns> public override double GetArea() { return Math.PI * this.radius * this.radius; } /// <summary> /// 円の周の長さを求める。 /// </summary> /// <returns>周</returns> public override double GetPerimeter() { return 2 * Math.PI * this.radius; } #endregion public override string ToString() { return string.Format( "Circle (c = {0}, r = {1})", this.center, this.radius); } } /// <summary> /// 2次元空間上の三角形をあらわすクラス /// </summary> class Triangle : Shape { Point a; Point b; Point c; #region 初期化 /// <summary> /// 3つの頂点の座標を与えて初期化。 /// </summary> /// <param name="a">頂点A</param> /// <param name="b">頂点B</param> /// <param name="c">頂点C</param> public Triangle(Point a, Point b, Point c) { this.a = a; this.b = b; this.c = c; } #endregion #region プロパティ /// <summary> /// 頂点A。 /// </summary> public Point A { get { return a; } set { a = value; } } /// <summary> /// 頂点B。 /// </summary> public Point B { get { return b; } set { b = value; } } /// <summary> /// 頂点C。 /// </summary> public Point C { get { return c; } set { c = value; } } #endregion #region 面積・周 /// <summary> /// 三角形の面積を求める。 /// </summary> /// <returns>面積</returns> public override double GetArea() { Point ab = b - a; Point ac = c - a; return 0.5 * Math.Abs(ab.X * ac.Y - ac.X * ab.Y); } /// <summary> /// 三角形の周の長さを求める。 /// </summary> /// <returns>周</returns> public override double GetPerimeter() { double l = Point.GetDistance(this.a, this.b); l += Point.GetDistance(this.a, this.c); l += Point.GetDistance(this.b, this.c); return l; } #endregion public override string ToString() { return string.Format( "Circle (a = {0}, b = {1}, c = {2})", this.a, this.b, this.c); } } /// <summary> /// Class1 の概要の説明です。 /// </summary> class Class1 { static void Main() { Triangle t = new Triangle( new Point(0, 0), new Point(3, 4), new Point(4, 3)); Circle c = new Circle( new Point(0, 0), 3); Show(t); Show(c); } static void Show(Shape f) { Console.Write("{0}\n", f); Console.Write("{0}\n", f.GetArea()); Console.Write("{0}\n", f.GetPerimeter()); } }
必要な箇所(Shape クラスの部分)だけ抜粋。
/// <summary> /// 2次元空間上の図形を表すクラス。 /// 三角形や円等の共通の抽象基底クラス。 /// </summary> abstract class Shape { public abstract double GetArea(); public abstract double GetPerimeter(); }
多態性の問題 1の Shape
クラスをインターフェース化せよ。
Triangle
や Shape
関係の例題は一応、これで完成形。
余力があれば、楕円、長方形、平行四辺形、(任意の頂点の)多角形等、さまざまな図形クラスを作成せよ。 また、これらの図形の面積と周の比を計算するプログラムを作成せよ。
三角形、円に加え、多角形を実装した物を示します。
using System; /// <summary> /// 2次元の点をあらわす構造体 /// </summary> struct Point { double x; // x 座標 double y; // y 座標 #region 初期化 /// <summary> /// 座標値 (x, y) を与えて初期化。 /// </summary> /// <param name="x">x 座標値</param> /// <param name="y">y 座標値</param> public Point(double x, double y) { this.x = x; this.y = y; } #endregion #region プロパティ /// <summary> /// x 座標。 /// </summary> public double X { get { return this.x; } set { this.x = value; } } /// <summary> /// y 座標。 /// </summary> public double Y { get { return this.y; } set { this.y = value; } } #endregion #region 演算子 /// <summary> /// ベクトル和 /// </summary> /// <param name="a">点A</param> /// <param name="b">点B</param> /// <returns>和</returns> public static Point operator +(Point a, Point b) { return new Point(a.x + b.x, a.y + b.y); } /// <summary> /// ベクトル差 /// </summary> /// <param name="a">点A</param> /// <param name="b">点B</param> /// <returns>和</returns> public static Point operator -(Point a, Point b) { return new Point(a.x - b.x, a.y - b.y); } #endregion /// <summary> /// A-B 間の距離を求める。 /// </summary> /// <param name="a">点A</param> /// <param name="b">点B</param> /// <returns>距離AB</returns> public static double GetDistance(Point a, Point b) { double x = a.x - b.x; double y = a.y - b.y; return Math.Sqrt(x * x + y * y); } public override string ToString() { return "(" + x + ", " + y + ")"; } } /// <summary> /// 2次元空間上の図形を表すクラス。 /// 三角形や円等の共通の抽象基底クラス。 /// </summary> interface Shape { double GetArea(); double GetPerimeter(); } /// <summary> /// 2次元空間上の円をあらわすクラス /// </summary> class Circle : Shape { Point center; double radius; #region 初期化 /// <summary> /// 半径を指定して初期化。 /// </summary> /// <param name="r">半径。</param> public Circle(Point center, double r) { this.center = center; this.radius = r; } #endregion #region プロパティ /// <summary> /// 円の中心。 /// </summary> public Point Center { get { return this.center; } set { this.center = value; } } /// <summary> /// 円の半径。 /// </summary> public double Radius { get { return this.radius; } set { this.radius = value; } } #endregion #region 面積・周 /// <summary> /// 円の面積を求める。 /// </summary> /// <returns>面積</returns> public double GetArea() { return Math.PI * this.radius * this.radius; } /// <summary> /// 円の周の長さを求める。 /// </summary> /// <returns>周</returns> public double GetPerimeter() { return 2 * Math.PI * this.radius; } #endregion public override string ToString() { return string.Format( "Circle (c = {0}, r = {1})", this.center, this.radius); } } /// <summary> /// 2次元空間上の三角形をあらわすクラス /// </summary> class Triangle : Shape { Point a; Point b; Point c; #region 初期化 /// <summary> /// 3つの頂点の座標を与えて初期化。 /// </summary> /// <param name="a">頂点A</param> /// <param name="b">頂点B</param> /// <param name="c">頂点C</param> public Triangle(Point a, Point b, Point c) { this.a = a; this.b = b; this.c = c; } #endregion #region プロパティ /// <summary> /// 頂点A。 /// </summary> public Point A { get { return a; } set { a = value; } } /// <summary> /// 頂点B。 /// </summary> public Point B { get { return b; } set { b = value; } } /// <summary> /// 頂点C。 /// </summary> public Point C { get { return c; } set { c = value; } } #endregion #region 面積・周 /// <summary> /// 三角形の面積を求める。 /// </summary> /// <returns>面積</returns> public double GetArea() { Point ab = b - a; Point ac = c - a; return 0.5 * Math.Abs(ab.X * ac.Y - ac.X * ab.Y); } /// <summary> /// 三角形の周の長さを求める。 /// </summary> /// <returns>周</returns> public double GetPerimeter() { double l = Point.GetDistance(this.a, this.b); l += Point.GetDistance(this.a, this.c); l += Point.GetDistance(this.b, this.c); return l; } #endregion public override string ToString() { return string.Format( "Circle (a = {0}, b = {1}, c = {2})", this.a, this.b, this.c); } } /// <summary> /// 自由多角形をあらわすクラス /// </summary> class Polygon : Shape { Point[] verteces; // 頂点 #region 初期化 /// <summary> /// 座標を与えて初期化。 /// </summary> /// <param name="verteces">頂点の座標の入った配列</param> public Polygon(params Point[] verteces) { this.verteces = verteces; } #endregion #region プロパティ /// <summary> /// 頂点の集合。 /// </summary> public Point[] Verteces { get { return this.verteces; } set { this.verteces = value; } } #endregion #region 面積・周 /// <summary> /// 三角形の面積を求める。 /// </summary> /// <returns>面積</returns> public double GetArea() { double area = 0; Point p = this.verteces[this.verteces.Length - 1]; for (int i = 0; i < this.verteces.Length; ++i) { Point q = this.verteces[i]; area += p.X * q.Y - q.X * p.Y; p = q; } return 0.5 * Math.Abs(area); } /// <summary> /// 三角形の周の長さを求める。 /// </summary> /// <returns>周</returns> public double GetPerimeter() { double perimeter = 0; Point p = this.verteces[this.verteces.Length - 1]; for (int i = 0; i < this.verteces.Length; ++i) { Point q = this.verteces[i]; perimeter += Point.GetDistance(p, q); p = q; } return perimeter; } #endregion public override string ToString() { System.Text.StringBuilder sb = new System.Text.StringBuilder(); sb.AppendFormat("Polygon ({0}", this.verteces[0]); for (int i = 1; i < this.verteces.Length; ++i) { sb.AppendFormat(", {0}", this.verteces[i]); } sb.Append(")"); return sb.ToString(); } } /// <summary> /// Class1 の概要の説明です。 /// </summary> class Class1 { static void Main() { Triangle t = new Triangle( new Point(0, 0), new Point(3, 4), new Point(4, 3)); Circle c = new Circle( new Point(0, 0), 3); Polygon p1 = new Polygon( new Point(0, 0), new Point(3, 4), new Point(4, 3)); Polygon p2 = new Polygon( new Point(0, 0), new Point(0, 2), new Point(2, 2), new Point(2, 0)); Show(t); Show(c); Show(p1); Show(p2); } static void Show(Shape f) { Console.Write("図形 {0}\n", f); Console.Write("面積/周 = {0}\n", f.GetArea() / f.GetPerimeter()); } }
GUI 雛形プログラム(Graphic 用)をベースに、 画面上を何か図形が動き回るようなプログラムを作成せよ。 Windows のスクリーンセーバー「ライン アート」のような物を目指すとよい。
GUI 雛形プログラム(Graphic 用)自体が1つの回答例。