質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

オブジェクト指向

オブジェクト指向プログラミング(Object-oriented programming;OOP)は「オブジェクト」を使用するプログラミングの概念です。オブジェクト指向プログラムは、カプセル化(情報隠蔽)とポリモーフィズム(多態性)で構成されています。

Q&A

解決済

2回答

4696閲覧

オブジェクト指向を用いたテトリスの設計

mightyMask

総合スコア143

Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

オブジェクト指向

オブジェクト指向プログラミング(Object-oriented programming;OOP)は「オブジェクト」を使用するプログラミングの概念です。オブジェクト指向プログラムは、カプセル化(情報隠蔽)とポリモーフィズム(多態性)で構成されています。

0グッド

0クリップ

投稿2016/11/22 13:55

編集2016/11/22 14:18

###前提・仕様
上手なクラス設計をするためにアイディアをください。

ここでのテトリスの仕様は以下のものとします。(ワールドルールに準拠)
また、すでに実装済みのものは●,まだ実装していないものは○で表記しています。

●4つのブロックを一纏りにしたものをテトリミノと呼び、テトリミノは7種類ある。
●テトリミノを一瞬で下まで落とし、設置させる事が可能。これをハードドロップと呼ぶ。
●ハードドロップをした際、どこにミノが設置されるのかを表したものをゴーストと呼ぶ。
○ゴーストを表示するかどうかは設定できる。
○地面に着地してからは、すぐには設置されない(ハードドロップの際を除く)。左右に動かすか、回転することにより、設置されるまでの時間が延長される。ただし、延長できる回数は14回まで。15回目の延長をしようとした場合、強制的に設置される。
○ミノを着地及びラインを消去した際、combo,t-spin等と呼ばれる特殊な条件に当てはまる場合がある。
○ミノを回転させる時のルールは、その場で回転できない場合、ミノの座標をずらす。座標をずらしてもその場に存在できない場合、さらにずらす。これを4回判定し、それでもその場に存在できない場合は回転しない。その際、座標をx軸,y軸に対してどれだけずらすかというのは、それぞれのミノ毎に異なり、さらにどの向き(上,右,下,左)からどっち回転(時計,反時計)に回転するかでも異なり、何回目の判定かという事によっても異なる。つまり、座標をずらすルールは、742*4で224種類ある。このルールのことをSRS(スーパーローテーションシステム)と呼ぶ。
●ミノの選ばれ方は、必ず7種類のミノが均等に出てくるようになっている。具体的には、7種類のミノがランダム順に選ばれていき、1週したらまたランダム順に選ばれていく。
●次に出てくるミノを数個先まで見ることができる。これをネクストと呼ぶ。
●不要なミノを1つだけ取ってておくことができ、必要になったときにいつでも入れ替えて使うことができる。ただし使用した後は次のテトリミノが出てくるまでもう一度使用することができなくなる。

###質問
1.テトリミノはどう扱うのが上手な考え方でしょう。
1.1.まず、テトリミノの種類を表す enum TetKindというようなものは色々な場所で必要になってくるのでこれを作るのは正解でしょうか。

そして、テトリミノクラスを作るのに考えられるのは、
・Minoクラス を作り、コンストラクタの引数で TetKindを取る。(ソースではこれを採用している)
・Minoクラス(抽象) を作り、他に7つクラスを作り継承させる。
・Minoインターフェイス を作り、7つのクラスを作り実装させる。

1.2.自分が考えられるのはこれくらいでした。他にもありますでしょうか。
1.3.また、どれがどの理由で一番いい方法といえるでしょうか。
1.4.また、SRSの情報(224種の回転法則)はどこにどのような形式で保持しておくべきでしょうか。

2.Fieldクラスと、 先ほどのミノクラスはどうゆう関係にするのがいいでしょうか。フィールドクラスのメンバ変数としてミノクラスを持つのが良いのでしょうか。ミノの形を変形させて回転させるというメソッドはミノクラスが持っているべきだと思いますが、実際に回転させるには、フィールドを把握してないと出来ません。実際に回転するという関数をフィールドが持つべきなのでしょうか。それだとミノクラスとフィールドクラスを行ったり来たりしてしまいます。

3.また、ゴーストはミノクラスの変数としてフィールドが持っているものとして大丈夫でしょうか。

4.フィールドクラスは外部のクラス( GUIを担当しているクラス等 )の属性として持つものとして設計するのが良いと思いますが、ミノを置いたという事や列を消去したという事、その際t-spin等特殊な条件を満たしているかどうかという事を外部のクラスへ通知しなくてはなりません。この場合どのような方法を用いるのが適切でしょうか。

###ソースコード

java

1public enum TetKind 2{ 3 Empty, 4 Ghost, 5 Z, 6 L, 7 O, 8 S, 9 I, 10 J, 11 T; 12 13 public static int cnt = 7; 14}

java

1public class Mino 2{ 3 // 属性 4 TetKind type; 5 private int x, y; // 左上の座標 6 private boolean[][] shape; 7 8 // コンストラクタ 9 Mino( TetKind type ) 10 { 11 this.type = type; 12 13 switch( type ) 14 { 15 case Z: 16 x = 3; y = 1; 17 shape = new boolean[][] 18 { { true , true , false }, // ■■□ 19 { false, true , true }, // □■■ 20 { false, false, false } }; // □□□ 21 break; 22 23 case L: 24 x = 3; y = 1; 25 shape = new boolean[][] 26 { { false, false, true }, // □□■ 27 { true , true , true }, // ■■■ 28 { false, false, false } }; // □□□ 29 break; 30 31 case O: 32 x = 4; y = 1; 33 shape = new boolean[][] 34 { { true , true }, // ■■ 35 { true , true } }; // ■■ 36 break; 37 38 case S: 39 x = 3; y = 1; 40 shape = new boolean[][] 41 { { false, true , true }, // □■■ 42 { true , true , false }, // ■■□ 43 { false, false, false } }; // □□□ 44 break; 45 46 case I: 47 x = 3; y = 1; 48 shape = new boolean[][] 49 { { false, false, false, false }, // □□□□ 50 { true , true , true , true }, // ■■■■ 51 { false, false, false, false }, // □□□□ 52 { false, false, false, false } }; // □□□□ 53 break; 54 55 case J: 56 x = 3; y = 1; 57 shape = new boolean[][] 58 { { true , false, false }, // ■□□ 59 { true , true , true }, // ■■■ 60 { false, false, false } }; // □□□ 61 break; 62 63 case T: 64 x = 3; y = 1; 65 shape = new boolean[][] 66 { { false, true , false }, // □■□ 67 { true , true , true }, // ■■■ 68 { false, false, false } }; // □□□ 69 break; 70 } 71 } 72 73 // メソッド 74 public Mino copy() 75 { 76 Mino ret = new Mino( this.type ); 77 ret.shape = copy( this.shape ); 78 ret.x = this.x; 79 ret.y = this.y; 80 81 return ret; 82 } 83 84 private boolean[][] copy( boolean[][] args ) 85 { 86 boolean[][] ret = new boolean[args.length][args[0].length]; 87 88 for( int x=0 ; x< args .length ; x++ ){ 89 for( int y=0 ; y< args[0].length ; y++ ){ 90 ret[y][x] = args[y][x]; 91 } 92 } 93 94 return ret; 95 } 96 97 // 引数の座標にミノがあるか 98 boolean isExistMino( int x, int y ) 99 { 100 if( x < this.x || x >= this.x + shape.length || 101 y < this.y || y >= this.y + shape.length ){ 102 return false; 103 }else{ 104 return shape[ y - this.y ][ x - this.x ]; 105 } 106 } 107 108 // 右回転(変形) 109 void rotateRight() 110 { 111 boolean[][] temp = copy( shape ); 112 for( int x = 0 ; x < shape.length ; x++ ){ 113 for( int y = 0 ; y < shape.length ; y++ ){ 114 shape[y][x] = temp[shape.length -x -1][y]; 115 } 116 } 117 } 118 119 // 左回転(変形) 120 void rotateLeft() 121 { 122 boolean[][] temp = copy( shape ); 123 for( int x = 0 ; x < shape.length ; x++ ){ 124 for( int y = 0 ; y < shape.length ; y++ ){ 125 shape[y][x] = temp[x][shape.length -y -1]; 126 } 127 } 128 } 129 130 void moveRight() 131 { 132 x++; 133 } 134 135 void moveLeft() 136 { 137 x--; 138 } 139 140 void moveUp() 141 { 142 y--; 143 } 144 145 void moveDown() 146 { 147 y++; 148 } 149}

java

1public class Field extends Thread 2{ 3 // 定数 4 final public static int ROW = 22; 5 final public static int COL = 10; 6 7 // 属性 8 private TetKind[][] map = new TetKind[ROW][COL]; 9 10 private Mino mino; 11 private Mino ghost; 12 13 private TetKind[] order = { TetKind.Z, TetKind.L, TetKind.O, TetKind.S, TetKind.I, TetKind.J, TetKind.T }; 14 private int orderNow = 0; // orderのカウンタ変数 15 16 private TetKind[] next = new TetKind[ TetKind.cnt ]; 17 private TetKind hold = TetKind.Empty; 18 private boolean holdFlag; 19 20 public long rate = 1000; 21 22 // コンストラクタ 23 public Field() 24 { 25 // フィールドを全て空にする 26 for( int y=0 ; y< ROW ; y++ ){ 27 for( int x=0 ; x< COL ; x++ ){ 28 map[y][x] = TetKind.Empty; 29 } 30 } 31 32 orderShuffle(); 33 for( int i=0 ; i< TetKind.cnt ; i++ ){ 34 next[i] = order[i]; 35 } 36 37 spawn(); 38 start(); 39 } 40 41 // publicメソッド 42 public void rotateRight() 43 { 44 mino.rotateRight(); 45 if( !canExistMino( mino ) ){ 46 mino.rotateLeft(); 47 } 48 49 updateGhost(); 50 } 51 52 public void rotateLeft() 53 { 54 mino.rotateLeft(); 55 if( !canExistMino( mino ) ){ 56 mino.rotateRight(); 57 } 58 59 updateGhost(); 60 } 61 62 public void moveRight() 63 { 64 mino.moveRight(); 65 if( !canExistMino( mino ) ){ 66 mino.moveLeft(); 67 } 68 69 updateGhost(); 70 } 71 72 public void moveLeft() 73 { 74 mino.moveLeft(); 75 if( !canExistMino( mino ) ){ 76 mino.moveRight(); 77 } 78 79 updateGhost(); 80 } 81 82 public void softDrop() 83 { 84 mino.moveDown(); 85 if( !canExistMino( mino ) ){ 86 mino.moveUp(); 87 putBlock(); 88 } 89 } 90 91 public void hardDrop() 92 { 93 for( int y=0 ; y< ROW ; y++ ){ 94 for( int x=0 ; x< COL ; x++ ){ 95 if( ghost.isExistMino(x, y) ){ 96 map[y][x] = mino.type; 97 } 98 } 99 } 100 deleteLine(); 101 spawn(); 102 } 103 104 public void hold() 105 { 106 if( !holdFlag ){ 107 return; 108 } 109 110 if( hold == TetKind.Empty ){ 111 hold = mino.type; 112 spawn(); 113 }else{ 114 TetKind temp = hold; 115 hold = mino.type; 116 mino = new Mino( temp ); 117 } 118 119 holdFlag = false; 120 updateGhost(); 121 } 122 123 // 引数の座標のブロックの種類を得る 124 public TetKind getMap( int x, int y ) 125 { 126 if( mino.isExistMino(x, y) ){ 127 return mino.type; 128 } 129 else if( ghost.isExistMino(x, y) ){ 130 return TetKind.Ghost; 131 } 132 else{ 133 return map[y][x]; 134 } 135 } 136 137 // ホールドのブロックの種類を得る 138 public TetKind getHold() 139 { 140 return hold; 141 } 142 143 // ネクストのブロックの種類を得る 144 public TetKind getNext( int n ) 145 { 146 return next[n]; 147 } 148 149 // privateメソッド 150 @Override public void run() 151 { 152 while( true ){ 153 try{ sleep( rate ); }catch( Exception e ){} 154 softDrop(); 155 } 156 } 157 158 private void orderShuffle() 159 { 160 java.util.Random r = new java.util.Random(); 161 for( int i=0 ; i< order.length ; i++ ){ 162 int rand = r.nextInt( order.length ); 163 TetKind temp = order[rand]; 164 order[rand] = order[i]; 165 order[i] = temp; 166 } 167 } 168 169 private void spawn() 170 { 171 // 最後まで行ったら最初から 172 if( orderNow == order.length ){ 173 orderNow = 0; 174 orderShuffle(); 175 } 176 177 mino = new Mino( next[0] ); 178 179 // ネクストを更新 180 for( int i=0 ; i< TetKind.cnt -1 ; i++ ){ 181 next[i] = next[i+1]; 182 } 183 next[TetKind.cnt -1] = order[orderNow]; 184 185 orderNow++; 186 updateGhost(); 187 holdFlag = true; 188 } 189 190 // ブロックを設置する 191 private void putBlock() 192 { 193 for( int y=0 ; y< ROW ; y++ ){ 194 for( int x=0 ; x< COL ; x++ ){ 195 if( mino.isExistMino(x, y) ){ 196 map[y][x] = mino.type; 197 } 198 } 199 } 200 deleteLine(); 201 spawn(); 202 } 203 204 // ブロックが揃った列を消去 205 private void deleteLine() 206 { 207 outside: for( int y = 0 ; y < ROW ; y++ ){ 208 // その列が揃ってないなら次の列 209 for( int x=0 ; x < COL ; x++ ){ 210 if( map[y][x] == TetKind.Empty ){ 211 continue outside; 212 } 213 } 214 215 // それより上の列を落とす 216 for( int ty = y ; ty > 0 ; ty -- ){ 217 for( int x=0 ; x < COL ; x++ ){ 218 map[ty][x] = map[ty-1][x]; 219 } 220 } 221 222 // 一番上の列は全て空 223 for( int x=0 ; x < COL ; x++ ){ 224 map[0][x] = TetKind.Empty; 225 } 226 } 227 } 228 229 // ミノがその場所に存在できるかどうか 230 private boolean canExistMino( Mino arg ) 231 { 232 int cnt = 0; 233 for( int y= 0 ; y< ROW ; y++ ){ 234 for( int x= 0 ; x< COL ; x++ ){ 235 if( arg.isExistMino( x, y ) ){ 236 // マップ内に存在しているミノの数を数える 237 if( map[y][x] == TetKind.Empty ){ 238 cnt++; 239 } 240 // フィールド上のミノと重なっていたらfalse 241 else{ 242 return false; 243 } 244 } 245 } 246 } 247 248 // マップ内のミノが4ではない場合、 249 // ミノの一部がフィールド外にはみ出てしまっているためfalse 250 return cnt == 4 ? true : false; 251 } 252 253 private void updateGhost() 254 { 255 ghost = mino.copy(); 256 while( canExistMino( ghost ) ){ 257 ghost.moveDown(); 258 } 259 ghost.moveUp(); 260 } 261}

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

mightyMask

2016/11/22 14:18

ソースコードを載せ忘れていたため、丸投げと捉えられてしまったのでしょうか。ソースコードを載せました。
guest

回答2

0

ベストアンサー

すこし質問の量が多すぎるようです。

すべてに対して回答すると、量が多すぎておそらくきちんと理解できないでしょう。
基本的には、1つの内容について質問し、どうすればよいかが一言にまとまるような質問が答えやすいです。

そのうえで、わかっている点、疑問に思っている点を質問するとよいと思います。
同じ課題について何度も質問する方は珍しくありません。

個別に答えるのが面倒なので、オブジェクト指向に関する全般的な話をします。

●4つのブロックを一纏りにしたものをテトリミノと呼び、テトリミノは7種類ある。

これをオブジェクト指向にし易いように書き換えるとこうなります。

・テトリスミノは4つのブロックを持ち、7種類の持ち方が存在する

これを、クラス設計に活かすとこうなります。(一例として・・・)

・Tetriminoクラスはblock[4] Blocksフィールドを持ち、コンストラクタで予め指定されは7つの並びのいずれかが選択される。

更に、TetriminoクラスにGetGoust関数でGoustクラス受け取れるようにしたり、(回転出来ない時は無視される)SpinRight関数などテトリミノが出来ることを定義します。

重要な点は、具体的なモノ(Object)にたいして、名前をクラス名で定義して、モノの状態をFieldとし、出来ることをMethodとして定義することです。

言葉で、「OOはXXすることができる」「OOはZZをもつ」で定義していくと初心者にはやりやすいです。質問者さんの定義を見ているとクラス名から何を定義しているのかわからないのでアドバイスがしづらいです。

投稿2016/11/22 14:42

iwamoto_takaaki

総合スコア2883

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

次からは一つの内容について細かく質問していくことにします。

テトリミノは4つのブロックを持ち、7種類の持ち方が存在するというクラス設計についても疑問がありますので、まずはその質問からさせていただきました。
https://teratail.com/questions/56197?modal=q-comp
もし良ければ、こちらの質問もご覧になってくれればとても嬉しいです。

投稿2016/11/22 15:41

編集2016/11/22 15:48
mightyMask

総合スコア143

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問