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

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

ただいまの
回答率

90.75%

  • Java

    13122questions

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

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

解決済

回答 2

投稿

  • 評価
  • クリップ 1
  • VIEW 197

tarutarupop

score 11

お世話になっております。現在オセロゲームを作ろうと考えています。そこで盤面を、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などしか使っていないため、どこかで要素の追加や置き換え、削除を行ったりはしていません。(少なくとも自分が書いたコード内では)なぜこんな現象が起こるのでしょうか?

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

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

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 2

checkベストアンサー

+1

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

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

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/04/29 20:47

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

    キャンセル

  • 2018/04/29 21:22

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

    キャンセル

  • 2018/04/29 21:30

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

    キャンセル

  • 2018/04/30 02:32

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

    キャンセル

+1

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


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

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

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

@SuppressWarnings("serial")
class Cell extends JButton {
    // 質問の本題と関係ないので、distanceとpieceをpublicで定義しましたが、本来はGetter/Setterを定義する形の方が良いです。
    public final int[] distance;
    public int piece;// 駒

    public Cell(int j, int i, int j2) {
        this.distance = new int[] { j, i };
        this.piece = j2;
    }

    @Override
    public String toString() {
        return Arrays.toString(distance) + ":" + String.valueOf(this.piece);
    }
}

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

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

気になる点

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

  2. > CellはJButtonを継承したもので、盤面内での座標をint[] distanceとして持っています。
    JButtonは表示とボタンアクションの通知だけにして、JPanelと盤面の情報を管理するクラス(Boardクラス)を作成して、JPanelのイベントでアクションコマンドの引数を元に紐付けする形にもできるかと。

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

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

import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.util.Arrays;

public class A123942 {

    public static void main(String[] args) {
        Board b = new Board();
        System.out.println(b);
    }
}

class Board {
    private final int[][] board = new int[8][8];
    private final PropertyChangeSupport changes = new PropertyChangeSupport(this);

    Board() {
        board[3][3] = -1;
        board[4][4] = -1;
        board[3][4] = 1;
        board[4][3] = 1;

        // もしくはEnumを使うなら変数:bordの型を変更して以下の初期化でも
        // for(Piece[] x: board){
        // Arrays.fill(x, Piece.None);
        // }
        // board[3][3] = Piece.White;
        // board[4][4] = Piece.White;
        // board[3][4] = Piece.Black;
        // board[4][3] = Piece.Black;
    }

    public void addPropertyChangeListener(PropertyChangeListener listener) {
        changes.addPropertyChangeListener(listener);
    }

    public void removePropertyChangeListener(PropertyChangeListener listener) {
        changes.removePropertyChangeListener(listener);
    }

    public void setPiece(int x, int y, int s) {
        int oldValue = board[x][y];
        board[x][y] = s;
        // 変更イベントを発火
        this.changes.firePropertyChange("setPiece", oldValue, s);
    }

    @Override
    public String toString() {
        return Arrays.deepToString(board);
    }
}

enum Piece {
    Black("黒"), White("白"), None(" ");
    private final String label;

    Piece(String label) {
        this.label = label;
    }

    @Override
    public String toString() {
        return this.label;
    }
}

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/04/29 21:05

    すいません、説明不足の点があったようです。
    ・JButtonをGridlayoutで表示しているのですが、試したところButtonPanelでのような生成の仕方をするとboard.get(a).get(b)のaが行bが列になるようでした。自分の感覚としては座標は(x,y)の順で保持したかったため、生成時にiとjを逆にして、あえてdistanceが(x,y)の順に格納されるようにしています。

    1>「石を置くことができる位置」は数学でいうとこの集合のような感覚で使いたかったのでSetで管理しようと思いました。(今後の処理に順序が関係ないかなと思ったので...)
    2,3,4>確かに、Cellは処理しないので情報を持っている意味はありませんね...改善案をもとに少し見直してみます。具体的な指摘ありがとうございます。

    キャンセル

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

  • ただいまの回答率 90.75%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

  • 解決済

    javaのGUIのレイアウトについて

    自作のターン制バトル型のゲームの画面を作っています。mainScreen.javeのJFrameのJPanelに別のクラスJobSelectのボタンなどを追加したいのですがやり方が

  • 解決済

    国旗を表示させたい(続き)

    前提・実現したいこと btn [0][1][2]をクリックすると、それに対応した国旗が表示されるようにしたい。 ソースコード import java.awt.*;   

  • 解決済

    色のついたPanelの上にLabelの配置

    public class Picross extends JFrame implements ActionListener { int[][] questiona

  • 受付中

    [java]TextFieldの中身を引数として持ってくる場合

    [java]TextFieldの中身を引数として持ってくる場合どうしたらよいですか? TextFieldに書かれた文字をボタンが押されたら一時的に保存されるという風にしたいのです

  • 解決済

    クラスリストの比較でcontainsが動作してくれない

    containsを用いて2つのクラスリストを比較したいのですが、うまく動作してくれません。 class Order{ public int id; publi

  • 解決済

    Javaのプログラミングで詰まっています

    最近、独学でJavaの学習を始めた新参者です。 エクリプスを利用して自分でプログラムを書いているのですが エラーの出てる箇所の修正方法がわからず詰まっている状態です。 よろし

  • 解決済

    JFrameでのJPanelの切り替えについて

    前提・実現したいこと (例)Java(UIはJFrame)でゲームを作っているのですが、JPanelの切り替えをJFrameで行おうとしています。 しかし、JPanelの切り替

  • 解決済

    二択問題の作り方について質問です。

    以下の二択問題のプログラムについて質問です。 これは、swingを用いた二択問題です。将来的には四択問題にするつもりです。 プログラミング初心者なため、とても回りくどい書き方ですみ

同じタグがついた質問を見る

  • Java

    13122questions

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