[小西ホームページ]   [目次・索引]   [前の授業]   [次の授業]

情報処理IIIA(Javaプログラミング入門)第5回

目次 索引
5.1 アプリケーションとアプレットの引数(2)
5.1.1 アプレット・パラメタ
5.2 反復
5.2.1 while文
5.2.2 for文
5.2.3 反復の使用例
5.3 演習5
5.4 レポート課題
for文  paramタグ  while文  アプレット・パラメタ  繰返し文  反復  無限ループ  ループ制御変数  ループ文 

5.1 アプリケーションとアプレットの引数(2)

5.1.1 アプレット・パラメタ

前回の授業では、コマンドライン引数を用いて、Javaアプリケーションにデータを渡しました。 コマンドライン引数と同様に、アプレットに対してもデータを渡すことができます。 このデータを アプレット・パラメタapplet parameter ) とよびます。 「引数」と「パラメタ」は同じ概念だと思ってください。

次のプログラムは、正方形の左上の座標を受け取り、縦横50ピクセルの正方形を描くアプレットです。

DrawSquare.java
/* 1*/ import java.applet.*;
/* 2*/ import java.awt.*;
/* 3*/ 
/* 4*/ public class DrawSquare extends Applet {
/* 5*/     public void paint (Graphics g) {
/* 6*/         int x = Integer.parseInt(getParameter("cornerx"));
/* 7*/         int y = Integer.parseInt(getParameter("cornery"));
/* 8*/         g.drawRect(x, y, 50, 50);
/* 9*/     }
/*10*/ }
DrawSquare.html
<body style="background-color: white">
<hr>
<applet code="DrawSquare.class" width="300" height="200">
  <param name="cornerx" value="50">
  <param name="cornery" value="50">
</applet>
<hr>
<applet code="DrawSquare.class" width="300" height="200">
  <param name="cornerx" value="200">
  <param name="cornery" value="100">
</applet>
<hr>
</body>
Netscape:
File Edit View Go Window Help

Drawing a square
Drawing a square


Applet BlackBox running
図 5.1  ブラウザのイメージ

アプレットに渡すデータは、HTMLドキュメントの中に書きます。 その際に、データには名前をつける必要があります。 ここでは、正方形の左上の x 座標を cornerxy 座標を cornery とします。 HTMLドキュメントでは、 <param> タグを用い、

<param name="name" value="value">

という形式で、名前とデータの対応を表します。 この例では、座標が (50, 50) ですので、

<param name="cornerx" value="50">
<param name="cornery" value="50">

となります。 なお、 <param> タグに終了タグはありません。 最後に、これを <applet> タグで囲みますと、HTMLドキュメントが完成します。

アプレットでデータを受け取るには、式

Integer.parseInt(getParameter("name"))

を用います。 上記のプログラムの6行目と7行目で、変数 xy に、正方形の左上の x 座標と y 座標が格納されます。


5.2 反復

5.2.1 while文

前回の授業では、選択というプログラムの構成要素を紹介しました。 今日は、 反復iteration ) について説明します。 反復を表す文は、 繰返し文repetitive statement ) 、または ループ文loop statement ) とよばれます。

反復にはいくつか種類がありますが、「何々が成り立つ間、何々を繰り返す」というものが基本です。 この種の反復には while文while statement ) を使います。 while 文は以下の形をとります。

while (condition) {
    statement; ...
}

条件 condition が成り立っている間、文 statement ; ... が繰り返し実行されます。

ここで、Good morning!と10回出力するプログラムを考えます。 はじめは数え上げ方式です。 これは、変数 i に0を代入しておき、Good morning!と一回出力するごとに i の値を1増やすということを、 i の値が10未満の間繰り返すものです。

/* 1*/ class TenMornings {
/* 2*/     public static void main (String[] args) {
/* 3*/         int i;
/* 4*/         i = 0;
/* 5*/         while (i < 10) {
/* 6*/             System.out.println("Good morning!");
/* 7*/             i++;
/* 8*/         }
/* 9*/     }
/*10*/ }
b00a001@Ampere:~/java% java TenMornings
Good morning!
Good morning!
Good morning!
Good morning!
Good morning!
Good morning!
Good morning!
Good morning!
Good morning!
Good morning!
b00a001@Ampere:~/java%

5行目から8行目までの while 文は次のように実行されます。

1. 変数iの値は0。条件i < 10が成り立つので、Good morning!と出力し、iの値を1増やす。
2. 変数iの値は1。条件i < 10が成り立つので、Good morning!と出力し、iの値を1増やす。
...
10. 変数iの値は9。条件i < 10が成り立つので、Good morning!と出力し、iの値を1増やす。
11. 変数iの値は10。条件i < 10は成り立たないので、このwhile文の実行を終える。

次はカウントダウン方式です。 これは、変数 i に10を代入しておき、Good morning!と一回出力するごとに i の値を1減らすということを、 i の値が正の間繰り返すものです。

/* 1*/ class TenMornings2 {
/* 2*/     public static void main (String[] args) {
/* 3*/         int i;
/* 4*/         i = 10;
/* 5*/         while (i > 0) {
/* 6*/             System.out.println("Good morning!");
/* 7*/             i--;
/* 8*/         }
/* 9*/     }
/*10*/ }

5行目から8行目までの while 文は次のように実行されます。

1. 変数iの値は10。条件i > 0が成り立つので、Good morning!と出力し、iの値を1減らす。
2. 変数iの値は9。条件i > 0が成り立つので、Good morning!と出力し、iの値を1減らす。
...
10. 変数iの値は1。条件i > 0が成り立つので、Good morning!と出力し、iの値を1減らす。
11. 変数iの値は0。条件i > 0は成り立たないので、このwhile文の実行を終える。

数え上げ方式とカウントダウン方式のどちらがよいかは、問題によって変わります。 数え上げ方式のほうがよく使われますが、カウントダウン方式が適切な場合もあります。

注意: 上記のプログラムで、7行目を書き忘れたとしましょう。

/* 1*/ class InfiniteMornings {
/* 2*/     public static void main (String[] args) {
/* 3*/         int i;
/* 4*/         i = 10;
/* 5*/         while (i > 0) {
/* 6*/             System.out.println("Good morning!");
/* 7*/         }
/* 8*/     }
/* 9*/ }

このプログラムを実行しますと、変数 i の値は10のままですので、条件 i > 0 がずっと成り立ち、永遠にGood morning!と出力され続けることになります。 このような、いつまでも続く繰り返しを、 無限ループinfinite loop ) とよびます。 反復を使うときは、無限ループにならないように気をつける必要があります。 なお、誤って無限ループに陥ったときは、Ctrl-Cで強制終了してください。

5.2.2 for文

反復の種類の中には、繰り返す回数が明確なものがあります。 この場合、 ループ制御変数loop control variable ) とよばれる変数を増加(あるいは減少)させながら繰り返すのが一般的です。 for文for statement ) を用いますと、このような反復をコンパクトに書き表すことができます。 for 文は次のような形をとります。

for (statement1; condition; statement2) {
    statement3; ...
}

まず文 statement1 が一度だけ実行されます。 そして条件 condition が成り立っている間、文 statement3 ; ...statement2 が繰り返し実行されます。 while 文を使ってこの for 文を書きますと、次のようになります。

statement1;
while (condition) {
    statement3; ...
    statement2;
}

for 文を用いますと、Good morning!と10回出力するプログラムは次のように書けます。 数え上げ方式については、

/* 1*/ class TenMornings3 {
/* 2*/     public static void main (String[] args) {
/* 3*/         int i;
/* 4*/         for (i = 0; i < 10; i++) {
/* 5*/             System.out.println("Good morning!");
/* 6*/         }
/* 7*/     }
/* 8*/ }

です。 カウントダウン方式は、

/* 1*/ class TenMornings4 {
/* 2*/     public static void main (String[] args) {
/* 3*/         int i;
/* 4*/         for (i = 10; i > 0; i--) {
/* 5*/             System.out.println("Good morning!");
/* 6*/         }
/* 7*/     }
/* 8*/ }

となります。

while 文と for 文には本質的な差はありません。 繰返しの回数がはっきりしているときには for 文、そうでないときには while 文を使うのがよいでしょう。

5.2.3 反復の使用例

反復の使用例として、はじめに 1+2+…+100 の計算を行います。

この問題は、レジの計算をまねることで解決できます。 つまり、それまでの合計を表す変数 sum を用意して、初期値を 0 とします。 そして、 sum の値を 1 増やし、2 増やし、…と繰り返し、100 増やした時点の sum の値が答になるわけです。 アルゴリズムは次のようになります。

  1. ループ制御変数 i を宣言する。
  2. 合計を表す変数 sum を宣言し、初期値を 0 とする。
  3. i を 1 から 100 まで増加させながら、以下を繰り返す。{
  4.    sum の値を i 増やす。
  5. sum の値を出力する。

プログラムは以下のようになります。

/* 1*/ class Summation100 {
/* 2*/     public static void main (String[] args) {
/* 3*/         int i, sum = 0;
/* 4*/         for (i = 1; i <= 100; i++) {
/* 5*/             sum = sum + i;
/* 6*/         }
/* 7*/         System.out.println(sum);
/* 8*/     }
/* 9*/ }
b00a001@Ampere:~/java% java Summation100
5050
b00a001@Ampere:~/java%

次の例は、360 の約数をすべて求めるものです。

360 の約数が、1 から 360 までの間にあることは、数学的に分かっています。 したがって、1 から 360 までの数一つ一つに対して、360 がその数で割り切れるかどうかを判断すれば、約数がもれなく見つけられます。 アルゴリズムは次のようになります。

  1. ループ制御変数 i を宣言する。
  2. i を 1 から 360 まで増加させながら、以下を繰り返す。{
  3.   もし 360 が i で割り切れるならば、{
  4.      i の値を出力する。
  5.   }

プログラムは以下のようになります。

/* 1*/ class Divisors360 {
/* 2*/     public static void main (String[] args) {
/* 3*/         int i;
/* 4*/         for (i = 1; i <= 360; i++) {
/* 5*/             if (360 % i == 0) {
/* 6*/                 System.out.println(i);
/* 7*/             }
/* 8*/         }
/* 9*/     }
/*10*/ }
b00a001@Ampere:~/java% java Divisors360
1
2
3
4
5
6
8
9
10
12
15
18
20
24
30
36
40
45
60
72
90
120
180
360
b00a001@Ampere:~/java%

最後の例は、正方形のタイル模様を描くアプレットです。 アプレットの大きさは、幅300ピクセル、高さ200ピクセルとします。 正方形のサイズ(幅)は、アプレット・パラメタ(名前は size )を用いて与えます。

Square tile pattern
図 5.2  正方形のタイル模様(サイズ20)
Square tile pattern
図 5.3  正方形のタイル模様(サイズ50)

この模様は、正方形が敷き詰められているように見えます。 しかし、実際は垂直な線と水平な線が等間隔に描かれているだけです。 そこで、垂直な線を描く方法と水平な線を描く方法を考え、これを続けることでプログラムを完成させることにします。

垂直な線を等間隔に描くには、 x の値を増やしながら、座標 ( x , 0) と ( x , 200) を結ぶ直線を繰り返し描くとできます。 x の値は最初は0で、サイズ分だけ増やしながら、300未満の間繰り返します。 アルゴリズムは次のようになります。

  1. 座標を表す変数 x を宣言し、初期値を0とする。
  2. サイズを表す変数 s を宣言し、初期値をアプレット・パラメタ size の値とする。
  3. x が300未満の間、以下を繰り返す。{
  4.   座標 ( x , 0) と ( x , 200) を結ぶ直線を描く。
  5.    x の値を s 増やす。

プログラムは以下のようになります。

SquareTile.java(第1版)
/* 1*/ import java.applet.*;
/* 2*/ import java.awt.*;
/* 3*/
/* 4*/ public class SquareTile extends Applet {
/* 5*/     public void paint (Graphics g) {
/* 6*/         int x = 0;
/* 7*/         int s = Integer.parseInt(getParameter("size"));
/* 8*/         while (x < 300) {
/* 9*/             g.drawLine(x, 0, x, 200);
/*10*/             x = x + s;
/*11*/         }
/*12*/     }
/*13*/ }
SquareTile.html
<applet code="SquareTile.class" width="300" height="200">
  <param name="size" value="20">
</applet>
Vertical lines
図 5.4  垂直な線

垂直な線の場合と同様に、水平な線も描けます。 アルゴリズムは次のようになります。

  1. 座標を表す変数 y を宣言し、初期値を0とする。
  2. サイズを表す変数 s を宣言し、初期値をアプレット・パラメタ size の値とする。
  3. y が200未満の間、以下を繰り返す。{
  4.   座標 (0, y ) と (300, y ) を結ぶ直線を描く。
  5.    y の値を s 増やす。

プログラムは以下のようになります。

SquareTile.java(第2版)
/* 1*/ import java.applet.*;
/* 2*/ import java.awt.*;
/* 3*/
/* 4*/ public class SquareTile extends Applet {
/* 5*/     public void paint (Graphics g) {
/* 6*/         int y = 0;
/* 7*/         int s = Integer.parseInt(getParameter("size"));
/* 8*/         while (y < 200) {
/* 9*/             g.drawLine(0, y, 300, y);
/*10*/             y = y + s;
/*11*/         }
/*12*/     }
/*13*/ }
Horizontal lines
図 5.5  水平な線

垂直な線を描いた後で水平な線を描くというアルゴリズムで、最終的にプログラムが完成します。 変数の宣言が最初にまとめられたことに注意してください。

SquareTile.java(最終版)
/* 1*/ import java.applet.*;
/* 2*/ import java.awt.*;
/* 3*/
/* 4*/ public class SquareTile extends Applet {
/* 5*/     public void paint (Graphics g) {
/* 6*/         int x = 0;
/* 7*/         int y = 0;
/* 8*/         int s = Integer.parseInt(getParameter("size"));
/* 9*/         while (x < 300) {
/*10*/             g.drawLine(x, 0, x, 200);
/*11*/             x = x + s;
/*12*/         }
/*13*/         while (y < 200) {
/*14*/             g.drawLine(0, y, 300, y);
/*15*/             y = y + s;
/*16*/         }
/*17*/     }
/*18*/ }

HTMLドキュメントの <param> タグを変更し、正方形のサイズが変わることを確認してください。


5.3 演習5

以下のような、ひし形のタイル模様を描くアプレットを作成してください。 アプレットの大きさは、幅300ピクセル、高さ200ピクセルとします。 ひし形のサイズ(幅)は、アプレット・パラメタ(名前は size )を用いて与えます。 アルゴリズムは次のようにします。 (このアルゴリズムは、はみ出した部分は描かれないことを利用しています。)

  1. 座標を表す変数 x を宣言する。
  2. サイズを表す変数 s を宣言し、初期値をアプレット・パラメタ size の値とする。
  3. x の値を-200とする。
  4. x が300未満の間、以下を繰り返す。{
  5.   座標 ( x , 0) から右下方向に直線を描く。
  6.    x の値を s 増やす。
  7. x の値を0とする。
  8. x が500未満の間、以下を繰り返す。{
  9.   座標 ( x , 0) から左下方向に直線を描く。
  10.    x の値を s 増やす。
Diamond tile pattern
図 5.6  ひし形のタイル模様(サイズ20)
Diamond tile pattern
図 5.7  ひし形のタイル模様(サイズ50)

余力のある人は、六角形のタイル模様を描いてください。 ひし形の場合と同様に、アプレット・パラメタは六角形のサイズ(幅)を表すものとします。 また、アルゴリズムは自由とします。 (ヒント: 六角形の幅を sx としますと、高さ sysx ×2/√3 で与えられます。

int sx = Integer.parseInt(getParameter("size"));
int sy = (int) (sx * 2 / Math.sqrt(3));

と初期化するとよいでしょう。)

Hexagon tile pattern
図 5.8  六角形のタイル模様(サイズ20)
Hexagon tile pattern
図 5.9  六角形のタイル模様(サイズ50)

5.4 レポート課題

今日の演習5に従ってJavaプログラムを作成し、そのプログラムをkonishi@twcu.ac.jpあてにメールで提出してください。 メールには、学生番号、氏名、科目名、授業日(10/24)を明記してください。


[小西ホームページ]   [目次・索引]   [前の授業]   [次の授業]

2002年10月24日更新
konishi@twcu.ac.jp
Copyright (C) 2002 Zenjiro Konishi. All rights reserved.