Top / Graphics / 2017 / ex14AB

グラフィックス基礎及び実習 2017年度 第14回 課題A&B [edit]

課題A&Bについて [edit]

今までのまとめの演習として,「三目ならべ(oxゲーム)」を作りましょう. まずは,次のリンク先のクラスファイルを手元に保存して実行し,いろいろいじってみよう.

  • SammokuSample.class
    • 盤面の外や既に o/x が置いてある所を指定するとどうなる?
    • 勝ち/負け/引き分けの判定はしてないですね
  • SammokuGUISample.class
    • SammokuSampleクラス使ってます
    • 適当にボタンを押してみよう
    • 環境によっては,SammokuGUISampleのウィンドウを少し大きくしないとボタンに描かれた文字が見えないかも.

以下の課題で,段階を踏んで同じようなものを作ってみよう.

課題AのプログラムはGUIを使いませんが,課題BでGUIを作るのに使います.ソースの置き場所については,~/Graphics20XY/ か ~/Graphics20XY/g/ のどちらか好きな方に統一したらよいでしょう.

課題A(TA) 締切: 次回4講時開始直後 [edit]

Step0 Step1 Step2

まとめの演習Step0 -- Sammoku (ver.0) を作ろう [edit]

(^o^)/ まずはキー入力の処理だけのプログラムを作ってみよう

次のような動作をするプログラムを作ろう.★から右側は解説.

  0 1 2
0| | | |
1| | | |       ★ 盤面を数字と縦棒で表示
2| | | |
横縦の順に値を入力してね(例: 2 1): 2 1     ★ 右側の 2 1 がキーボードからの入力 
(2,1)          ★ 入力された値を表示
  0 1 2 
0| | | |
1| | | |       ★ ver.0 では o や x の表示はなく,常に空の盤面を表示するだけ
2| | | |
横縦の順に値を入力してね(例: 2 1): 1 1
(1,1)
  0 1 2 
0| | | |
1| | | |
2| | | |
横縦の順に値を入力してね(例: 2 1): -1 2    ★ 盤面内の数字かどうかはチェックしたりしてない
(-1,2)
  0 1 2 
0| | | |
1| | | |
2| | | |
横縦の順に値を入力してね(例: 2 1): 99 100
(99,100)
  0 1 2 
0| | | |
1| | | |
2| | | |
横縦の順に値を入力してね(例: 2 1): 0 hoge    ★ 整数として解釈できない入力があると,再入力を促す
横縦の順に値を入力してね(例: 2 1): 

/(*_*) 次のことを守ってプログラムを考えよう

  1. クラス名は Sammoku とする.
  2. ver.0 では,盤面を表示するインスタンスメソッド(引数なし,戻り値なし,名前は自分で決めよう)と,mainメソッドの2つだけを定義する.
  3. mainメソッドは,以下のプログラム例を参考に作ろう.
import java.util.*;   // for Scanner class

public class Hoge{

    public static void main(String[] args){

	// キー入力を扱う Scanner クラス
	Scanner sc = new Scanner(System.in);

	// 空白を区切りとして2つの整数を入力するとその和を出力
	// 動作確認のためわざと変な入力をしてみるとよい
	while(true){
	    int x, y;
	    boolean done = false;
	    do{
		System.out.print("x y : ");
		try{
		    x = Integer.parseInt(sc.next());
		    y = Integer.parseInt(sc.next());
		    sc.nextLine(); // この行の残りを読みとばす
		    done = true;
		}catch(NumberFormatException e){
	    	    x = y = 0;
		    sc.nextLine(); // この行の残りを読みとばす
		    done = false;
		}
	    }while(!done);
	    System.out.println("x + y = " + (x + y));
	}

    }

}

まとめの演習Step1 -- Sammoku (ver.1) を作ろう [edit]

(^o^)/ キー入力で指定された位置に o や x が表示されるようにしよう

次のような動作をするプログラムを作ろう. 以下の動作例からわかるように,このver.1では,SammokuSample に近いふるまいをするけれど, 「キー入力で指定された位置が盤面内かどうか」,「そこに既にo/xがついているかどうか」,のチェックはしないものでよい(それらの処理はver.2で考えよう).盤面外を指定するとプログラムが例外を発生させて異常終了するとか,oやxを上書きできてしまうようなもので構わない.

  0 1 2 
0| | | |
1| | | |
2| | | |
横縦の順に値を入力してね(例: 2 1): 0 0
(0,0) に置いたで
  0 1 2 
0|o| | |
1| | | |
2| | | |
横縦の順に値を入力してね(例: 2 1): 0 0
(0,0) に置いたで
  0 1 2 
0|x| | |
1| | | |
2| | | |
横縦の順に値を入力してね(例: 2 1): 0 hoge
横縦の順に値を入力してね(例: 2 1): 0 100
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 100

/(*_*) 次のことを守ってプログラムを考えよう

以下の「クラスの設計を考えよう」をよく読んで,その指示に従ってください.よくできる人は全部一から考えたくなるでしょうが,与えられた仕様を満たすように作るのも大事ですから,まずは指示に従って課題をこなして,後で好きな設計を考えてみたらよいと思います.

クラスの設計を考えよう [edit]

/(?_?) Sammokuクラスのオブジェクトは,データとして何を持てばよい?

つまり,インスタンス変数やクラス変数としてどんなものを用意してどんな情報を格納するのがよい? → 例えば盤面はどう扱う? ○や×などの文字列で扱うのはややこしいからやめた方がよい → 適当に整数値を割り当てるのがよいだろう. といっても,マスの数ぶんの変数を一つ一つばらばらに用意するのはいやんですよねぇ → ということは…

/(*_*) 次のことを守ってプログラムを考えよう

  1. 盤面を表す変数などは外部から勝手にいじられたりしないように隠蔽しよう.

/(?_?) Sammokuクラスのオブジェクトにはどんな機能があればよい?

一つのメソッドがいろんな仕事をするように作ると使い勝手が悪いし保守もしにくい. 一つのメソッドはなるべく単純な仕事しかしないように作って組み合わせるのがよい. → そういうわけで,次のような5つの機能に分ける構成としてみよう(より細分化したい人はご自由にどうぞ)

  • 盤面の初期化: コンストラクタで
  • 指定された位置のマスの値(○や×を表す値)を返す:
  • 指定された位置のマスを指定された値(○や×を表す値)にする: マスの内容を表す変数の値を変更するだけ.盤面を表示するものではない(それは↓のメソッドの仕事)
  • 盤面を表示: ver.0 で作成したメソッドを改造
  • キー入力を受け付けて上記のメソッドたちを呼ぶ動作を繰り返す: mainメソッドで

まとめの演習Step2 -- Sammoku (ver.2) を作ろう [edit]

(^o^)/ 盤面外や既に○×が置いてある場所を指定すると SammokuSample と同様の動作をするように Sammoku を修正しよう.

そのためには,指定した位置に○×を置ける/置けないを判定する機能を追加して,それを使うのがよいでしょう. というわけで,次の仕様のメソッドを定義してそれを使うようにすること

boolean isBlank(int x, int y)
位置(x,y)が盤面内でかつその位置のマスが空いているなら true, さもなくば false を返す

課題B(TA) 締切: 次回4講時終了20分前 [edit]

まとめの演習Step3 -- SammokuGUI を作ろう

SammokuGUISample と同様のふるまいをするプログラム(SammokuGUI)を作ろう.

  • Sammokuクラスを利用する(Sammokuのインスタンスを生成してメソッドを呼び出す)プログラムにすること
  • JButtonも配列にして,イベント処理は次のようにするとよいかも.
    Object source = e.getSource();  // e はイベントオブジェクト
    for(int iy ...){
       for(int ix ...){
          if(source == (ix, iy)に対応したボタンオブジェクト){
             処理
          }
       }
    }
    

余裕のある人向けの注: 上記のようなイベント処理の考え方では,イベントソースとなるオブジェクトが非常にたくさんある(盤面が100x100とか)ような場合にはたくさんループを回らないといけなくて効率が悪いかもしれません. どのような設計にするとよいか考えてみるとよいでしょう. 気になる人は高橋に尋ねてください.


トップ   編集 凍結 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS
Last-modified: 2017-07-10 (月) 09:45:48 (13d)