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

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

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

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

Q&A

解決済

2回答

3356閲覧

二次元ArrayListを引数にして渡して処理したら、特定の一部の要素に変化が生じる

tarutarupop

総合スコア20

Java

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

0グッド

1クリップ

投稿2018/04/28 07:39

お世話になっております。現在オセロゲームを作ろうと考えています。そこで盤面を、JButtonを敷き詰めることで表現しようと考えています、具体的には次のようなコードです。CellJButtonを継承したもので、盤面内での座標をint[] distanceとして持っています。

<ButtonPanel> private ArrayList<ArrayList<Cell>> board = new ArrayList<ArrayList<Cell>>(8); ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ for(int i = 0; i < 8; i++) { ArrayList<Cell> s = new ArrayList<Cell>(8); for(int j = 0; j < 8; j++) { /* i = y座標 * j = x座標 */ Cell c; if( j == 3 && i== 3 || j == 4 && i== 4) { c = new Cell(j,i,-1); //白 }else if(j == 3 && i == 4 || j == 4 && i == 3) { c = new Cell(j,i,1); //黒 }else { c = new Cell(j,i,0); } c.addActionListener(this); c.setActionCommand(j +","+ i); this.add(c); s.add(c); } board.add(s); }

そしてこの後、盤面であるboardを、CheckCellsというクラス(置ける石の位置を探すためのクラス)に引数で送ります。

<CheckCells> private ArrayList<ArrayList<Cell>> board = new ArrayList<ArrayList<Cell>>(8); ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ public CheckCells(int a,ArrayList<ArrayList<Cell>> b) {     //コンストラクタ this.board.addAll(b); } ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ public HashSet<int[]> checkOk(){ //盤面(board)をもとに石を探す処理

この一連の流れではエラーなどは出ないのですが、checkOkで返ってくる結果がおかしいため、デバックで調べてみました。
その結果、生成時(ButtonPanel)では何の以上もないのですが、CheckCellsで処理に使われているboardでは、特定のCellが持つdistanceに変化が生じるのです。
具体的には、boardの3行目4番(board.get(3).get(4))のdistanceが[5,2]、4行目3番が[2,5]となったり
3行目4番が[3,5]、4行目3番[5,3]となったりする具合です。ほかの要素はまったく変わっていませんでした。

大変長くなってしまったのですが、簡単に言うと、生成時では問題なかったはずの二次元リストboardを、引く数として渡し処理で使ったとたんリスト内の特定の部分の要素が変化してしまう、というのが今回の問題点です。boardに対しては一貫してgetなどしか使っていないため、どこかで要素の追加や置き換え、削除を行ったりはしていません。(少なくとも自分が書いたコード内では)なぜこんな現象が起こるのでしょうか?

説明が下手で大変申し訳ありません。クラスが多めで処理も長いのですべてのクラスのコードは記載しませんが、不明な点があれば追記していきたいと思います。ご助力お願いいたします。

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

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

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

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

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

guest

回答2

0

ベストアンサー

CellはJButtonを継承したもので、盤面内での座標をint[] distanceとして持っています。

これがどうしても引っ掛かります。
例えboardから一貫してgetしか使用していなくても、getしたcellから座標を配列の参照でそのまま取得し、その数値を変化させた場合、そのcellすべての座標が影響を受けることになります。

投稿2018/04/28 19:02

swordone

総合スコア20651

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

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

tarutarupop

2018/04/29 11:47

つまり、boardにあるCell Aの持つdistance(int[])をgetして、int[]の変数 Bに入れたとします。そのBに対して、例えばB++などの操作をした場合、Cell Aの持つdistanceの情報が変わってしまうということでしょうか?
swordone

2018/04/29 12:22

そうです。getの段階で配列をコピーしていない限り、Cell Aの持つ配列、Bが指す配列は全く同じものです。Bに対して変更した場合、同じ配列を参照しているAにとっての配列も当然に変化します。
tarutarupop

2018/04/29 12:30

参照型変数ということを失念していました...checkOk内での処理でこれをやってしまっているので、それが原因だと思われます。ありがとうごさいます
swordone

2018/04/29 17:32

そもそもCell(石)が座標を持つ必要があるのかというのも疑問だが…
guest

0

質問文で引用している部分に関しては問題はないです。
デバック実行とのことなので、ウォッチ式を設定していませんか?
ブレイクポイントしたタイミングで式が評価されて結果が変わります。


質問文のコードではc = new Cell(j,i,-1);ijを逆に渡しているので、コンストラクタでそのまま設定していると仮定すると

board.get(3).get(4) このコードで取得できるのは、4行目の3番のマスの値では?

printデバックとして、Cell に以下のようなtoStringメソッドを追加してみてはどうでしょうか?

Java

1@SuppressWarnings("serial") 2class Cell extends JButton { 3 // 質問の本題と関係ないので、distanceとpieceをpublicで定義しましたが、本来はGetter/Setterを定義する形の方が良いです。 4 public final int[] distance; 5 public int piece;// 駒 6 7 public Cell(int j, int i, int j2) { 8 this.distance = new int[] { j, i }; 9 this.piece = j2; 10 } 11 12 @Override 13 public String toString() { 14 return Arrays.toString(distance) + ":" + String.valueOf(this.piece); 15 } 16}

ButtonPanelクラスに以下のコードを追加

Java

1 public void dump(ArrayList<ArrayList<Cell>> board) { 2 for (ArrayList<Cell> r : board) { 3 System.out.println(Arrays.toString(r.toArray(new Cell[0]))); 4 } 5 }

気になる点
0. CheckCellsクラスのcheckOkメソッドはHashSet<int[]>で値を返していますが、HashSetはセットの繰り返し順序について保証しません。

  1. CellはJButtonを継承したもので、盤面内での座標をint[] distanceとして持っています。

JButtonは表示とボタンアクションの通知だけにして、JPanelと盤面の情報を管理するクラス(Boardクラス)を作成して、JPanelのイベントでアクションコマンドの引数を元に紐付けする形にもできるかと。

  1. オセロなら盤面が固定(8*8)なため、生成時に要素が固定な多重配列(ジャグ配列)で管理するのも一つの手かと。これなら生成し直さない限り、要素数の変動は原理上起こりえません。

  2. CheckCellsという置ける石の位置を探すためのクラスで盤面情報を管理するクラスにひとまとめにしたほうがという2重管理を防げるかと。

Java

1import java.beans.PropertyChangeListener; 2import java.beans.PropertyChangeSupport; 3import java.util.Arrays; 4 5public class A123942 { 6 7 public static void main(String[] args) { 8 Board b = new Board(); 9 System.out.println(b); 10 } 11} 12 13class Board { 14 private final int[][] board = new int[8][8]; 15 private final PropertyChangeSupport changes = new PropertyChangeSupport(this); 16 17 Board() { 18 board[3][3] = -1; 19 board[4][4] = -1; 20 board[3][4] = 1; 21 board[4][3] = 1; 22 23 // もしくはEnumを使うなら変数:bordの型を変更して以下の初期化でも 24 // for(Piece[] x: board){ 25 // Arrays.fill(x, Piece.None); 26 // } 27 // board[3][3] = Piece.White; 28 // board[4][4] = Piece.White; 29 // board[3][4] = Piece.Black; 30 // board[4][3] = Piece.Black; 31 } 32 33 public void addPropertyChangeListener(PropertyChangeListener listener) { 34 changes.addPropertyChangeListener(listener); 35 } 36 37 public void removePropertyChangeListener(PropertyChangeListener listener) { 38 changes.removePropertyChangeListener(listener); 39 } 40 41 public void setPiece(int x, int y, int s) { 42 int oldValue = board[x][y]; 43 board[x][y] = s; 44 // 変更イベントを発火 45 this.changes.firePropertyChange("setPiece", oldValue, s); 46 } 47 48 @Override 49 public String toString() { 50 return Arrays.deepToString(board); 51 } 52} 53 54enum Piece { 55 Black("黒"), White("白"), None(" "); 56 private final String label; 57 58 Piece(String label) { 59 this.label = label; 60 } 61 62 @Override 63 public String toString() { 64 return this.label; 65 } 66}

投稿2018/04/28 14:39

編集2018/04/29 01:29
umyu

総合スコア5846

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

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

tarutarupop

2018/04/29 12:05

すいません、説明不足の点があったようです。 ・JButtonをGridlayoutで表示しているのですが、試したところButtonPanelでのような生成の仕方をするとboard.get(a).get(b)のaが行bが列になるようでした。自分の感覚としては座標は(x,y)の順で保持したかったため、生成時にiとjを逆にして、あえてdistanceが(x,y)の順に格納されるようにしています。 1>「石を置くことができる位置」は数学でいうとこの集合のような感覚で使いたかったのでSetで管理しようと思いました。(今後の処理に順序が関係ないかなと思ったので...) 2,3,4>確かに、Cellは処理しないので情報を持っている意味はありませんね...改善案をもとに少し見直してみます。具体的な指摘ありがとうございます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問