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

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

ただいまの
回答率

90.51%

  • Java

    13828questions

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

  • オブジェクト指向

    284questions

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

クラスを配列の添字に...?

解決済

回答 5

投稿

  • 評価
  • クリップ 0
  • VIEW 528

mightyMask

score 62

前提

teratail.com/questions/67133
ここで質問した者です。
javaのswingを用いてGUIの将棋ソフトを作成しています。 
ほぼ趣味プログラマーであり、プログラミング初心者です。 
厳格で純粋なオブジェクト指向に近いコードで綺麗に書く事を目標とします。 
そのため、早く軽快な動作は期待しません。 
ソースコードを短くするという事も期待しません。

クラスの関係

駒クラス(抽象)
歩、金、成桂などのクラス 
駒台クラス

質問

将棋の駒台クラスを作るにあたり、どのような設計にすれば良いものか悩んでいます。
ArrayListを使い駒台が所持している駒を保持するという方法を取ろうと思っていましたが、以下のような設計の方が色々と都合が良いのです。
駒台に乗る駒は飛、角、金、銀、桂、香、歩の7種類しかありません。
そこで、この7種の駒をそれぞれ何枚ずつ持っているかという事をint[7]という配列のようなもので管理する。
この方法で実現したいのですが、この構造だと困ることもあるわけです。
駒台クラスに必要なメソッドとして例えば、駒大に駒を追加する(引数は駒クラス)というものがあります。
引数から、配列のどの要素に+1するのかというのを決定するにはif/switchで条件分岐するという方法しか思いつきません。
配列名[引数で受け取った駒クラス] ++;この様に処理できればうまくいくわけですが...
javaのハッシュマップ機能を使えば実現できるわけですが、クラスを取得し、それをキーとするっていうのは美しくないし綺麗じゃないんですよね。
(クラスを取得する事をリフレクションと言うのでしょうか?)
そもそもクラスを配列の添字として使うのは良いやり方なのでしょうか。

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

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

回答 5

checkベストアンサー

+1

こんにちは。

駒クラスで参照しているインスタンスから駒台[0]駒台[6]へのマッピングが必要になります。
そのために方法の1つは質問で書かれている方法ですね。他にも様々な方法があります。

  • 各駒クラスの派生クラスにstaticなint型への参照を持ち、各駒台[n]への参照を設定する。
  • 先程の質問で回答した駒側で定義したインデックス番号を使う。
  • リフレクションで駒のクラス名を取り出し、名前に対してマッピングする。
    などなど。

投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2017/02/25 22:10

    1つ目の方法はそれぞれの駒クラスにまたそれぞれ子クラスを作ると言う事でしょうか。局面クラスがその子クラスを40つ保持し、駒の所在地ははその子クラスが保持するという事でしょうか。
    んーよく分かりませんがなんだか回りくどい事をすることになると思えますが、どうなんでしょう。
    2つ目のインデックス番号をつけると言うのはZuishinさんが仰られる様になんだか美しくない様に思えます。
    3つ目もなんだか気持ちの良い実装方法とは思えないんです。
    厳格で純粋なオブジェクト指向で設計するなら、リフレクションやキーマップなんかは必要ないものだというのが私の考えです。
    Featherweight Javaという言語があるらしいですが、私がイメージする厳格で純粋なオブジェクト指向に一番近いもがこれです。
    私は英語が絶望的に苦手なので、Featherweight Javaというものがよくわからなかったため質問には載せませんでしたが、http://tarao.hatenablog.com/entry/20100419/1271645340で説明されている様なものだと思います。

    キャンセル

  • 2017/02/25 22:55

    > 局面クラスがその子クラスを40つ保持し、駒の所在地ははその子クラスが保持するという事でしょうか。

    違います。
    駒クラスは抽象クラスですよね。ぞれを派生した金クラスや銀クラス等にstatic変数を追加します。
    プログラム起動時等に、そのstatic変数へ駒台[n]への参照を設定しておけば、後は「引数の駒クラス.static参照変数++;」でaddできます。至極簡単です。

    インデックス番号を使う方法も下記要件に対しては何ら問題なく使えます。
    「配列名[引数で受け取った駒クラス] ++;この様に処理できればうまくいくわけですが... 」

    しかし、各配列の要素に対応するクラスを特定することが必要なら、どの案を使ってもなにか工夫が必要です。名前で対応しようが数値で対応しようが同じことです。
    mightyMaskさんのもやもやは、この逆引きの要件を定めていないことから来ているのかも知れませんね。

    キャンセル

  • 2017/02/25 23:01

    > Featherweight Javaという言語があるらしいですが、私がイメージする厳格で純粋なオブジェクト指向に一番近いもがこれです。

    なるほど。実用的な話ではなく、学術的な話をされているのですね。
    すいません。学術的な私の知識は30年くらい古いのでお役には立てそうにないです。

    キャンセル

+1

駒をenumで作成して、数の記録はEnumMapを使うと良いです。

「クラスを取得する」というのは、全種類の駒をクラスとして定義しているからですよね?
enumにすればそれぞれが「値」になるのでさほど違和感なくMapに組み込めます。
コンストラクタを用意して初期化を行えるようにしたり、
共通の抽象メソッドを用意し、それを各列挙でオーバーライドすることもできます。

public enum Piece {
    FU(1) {
        // オーバーライドなど
    }
    KIN(2) {
        // オーバーライドなど
    }
    ...
    private final int x;
    private Piece (int i) { //コンストラクタはprivate限定
        x = i;
    }
}
---

Map<Piece, Integer> table = new EnumMap<>(Piece.class);
table.merge(Piece.FU, 1, Integer::sum);

投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

+1

私に言わせれば数字を添え字にする方が美しくないと思います。
駒と数字には何の関連もありません。

駒クラスを作り、そこから派生した歩クラスを作り、getClass() あるいは toString() したものをキーにすればいいではありませんか。

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2017/02/25 21:35

    将棋の駒の種類が増えることは考えにくいことですが、ありえないことではありません。将棋から派生した別のゲームに対応する状況はよくあることです。その場合、駒と番号を関連づけていたら、駒と番号の対応に依存している部分を全ソースから見つけて必要に応じて修正しなければなりません。関連付けなければその作業は不要になります。

    キャンセル

  • 2017/02/25 21:43

    はいそうです。私も数字を添字にしようとは思っていません。
    数字を添字にすると美しくないので今の所はgetClassでクラスを取得しハッシュマップのキーとして使うという方法をとっています。
    厳格で純粋なオブジェクト指向に近いソースコードを目標としているので、数字を使うよりはマシですが、どちらの方法も美しいやり方とは思えません。

    キャンセル

  • 2017/02/25 23:12

    何が美しくて何が美しくないのか基準がさっぱりわかりませんが、純粋で厳格なオブジェクト指向ということになると、if や switch はどうなんでしょうね? どちらも純粋な手続きであり、オブジェクトに対するメッセージではありません。

    キャンセル

  • 2017/02/25 23:25

    mightyMask さんの言われる「厳格で純粋なオブジェクト指向」は通常使われる意味での「厳格で純粋なオブジェクト指向」と乖離があるように感じます。まず mightyMask 風オブジェクト指向の定義から始めたら良いのではないでしょうか?共通の用語を使わなければ話は通じません。

    キャンセル

0

みなさんと同じようなことに過ぎませんが、「あるものに対する関連情報をenumとして宣言的に定義」という方法があります。本件についていえば駒に関連する色々な情報があるように思えるのであちこちの連想コレクションを使って分散して定義するよりは一括して集中定義できるので自分は好んで使います。これがオブジェクト指向的かどうかと言われれば「駒の種類」をどんなクラスとして捉えるか如何にかかると思います。

メタ情報の代表はクラスオブジェクトですがクラスメソッドやクラスフィールドが必ずしも都合よく定義できない(※)のでメタ情報を保持するなんらかのメタクラスがほしくなります。必ずしもenumでなくてもよいのですがインスタンスの宣言が

static final Meta 王 = new Meta("王", ...);

ではなく、

王(...),

と書けば済むというだけの理由でenumの方が若干短く書けます。

enum 駒の種類 {
  王(...),
  金(..., 0),
  銀(..., 1),
  ...
  歩(..., 6),
  ;
  private int komadaiIndex;

  駒の種類(...) { this(..., -1); }

  駒の種類(..., int komadaiIndex) {
    ...
    this.komadaiIndex = komadaiIndex;
  }

  ...

  public int getKomadaiIndex() {
    if (komadaiIndex == -1)
      throw new InternalError(name() + " has no komadaiIndex");
    return komadaiIndex;
  }
}

classModel {
  public abstract 駒の種類 get駒の種類();
  ...
}

※:クラスメソッドやクラスフィールドが必ずしも都合よく定義できない
例えばstaticメソッドやstaticフィールドをクラスメソッド・クラスフィールドにみたてて使える場合もあると思いますがこれらは継承できないので、以下のように書けないのです。

Class<? extends 駒Model> 駒ModelClass = ...;
int komadaiIndex = 駒ModelClass.getKomadaiIndex();

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

0

盤面と駒台を勘違いしていたので回答をごそっと編集。(前の回答は、編集履歴を参照ください。)
ただ、基本的な考えは変わらず。
盤面、駒台に存在する駒オブジェクトのリストと、
プレイヤー、プレイヤーが操作可能な駒オブジェクトのリストという概念が存在すれば。
駒の数自体を管理する必要はなく、必要な時にリストから集計する形でよいと考えています。

1.プレイヤーが、操作可能な駒のリストを持っているとして、
そのリストの中から、1つの駒オブジェクトを選択。
2.ゲームの進行を管理するゲームマスタークラスがいるとして、
ゲームマスターは、その駒オブジェクトが、盤面、駒台のどちらに含まれているか確認、
駒を配置できる位置を返却。
3.プレイヤーは、その位置の中から駒を置く場所を指定する。

といった流れを考えていました。

投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2017/02/27 12:19

    駒台というのは盤面のことではなく、手駒を置く台のことです。

    キャンセル

  • 2017/02/27 12:35

    ああ、検索して画像がぱっと見盤面に見えたから勘違いしてました。
    修正しますね。

    キャンセル

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

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

関連した質問

  • 解決済

    javaで、ある文字列が何文字目に存在するか正規表現でチェックしたい

    javaのプログラムである文字列が何文字目に含まれるかをチェックしたいのですが、 正規表現で実現するにはどうしたら良いでしょうか? (例) ある文字列が"test"でチェック対象文

  • 解決済

    JavaでグローバルIPアドレスを取得したい

    javaでクライアントマシンのグローバルIPアドレスを取得したいのですが、 以下のやり方以外でIPアドレスを取得する方法はあるのでしょうか? String ipAddr = ja

  • 解決済

    WebDriverでアラートダイアログを操作したい

    Selenium2 WebDriverを使った自動テストについて質問です。 以下のようなことをJavaのコードで実装したいのですが、可能でしょうか? ・ある画面にアラートのダイア

  • 解決済

    個別に乱数を生成したい

    下記のソースコードで実行すると、4つの点が現れcounterが100の倍数になる度にそれぞれの点が上下左右のうち1方向に進む事を期待していたのですが、実際に実行してみると、4つの点

  • 解決済

    抽象クラスはなぜ必要か?

    Javaプログラミングを勉強しています。 抽象クラスについて疑問を持ちました。 結論から言うと、 ・抽象クラスって必要でしょうか? ・現場でそんなに使っているのでしょうか?

  • 受付中

    Javaのスーパークラスについて

    Javaのスーパークラスについての質問です。 課題でサンプル問題のコピーをして実際に動くことを確認するのですが java.lang.NoClassDefFoundError: 

  • 受付中

    has-aの関係が分かりません

    Main.Javaの最後の文にあるh.sword.nameの意味が分かりません。参考書にメモリをイメージするようにとありますが、イメージすることが難しいです。 // まずSwo

  • 受付中

    【Java】Elementクラスのメソッド:setIdAttributeが見つからない

    JavaでXML出力を実装中なのですが、Elementタグについて質問です。 以下参考サイトのソースを実装したところ、Elementクラスのメソッド:setIdAttributeが

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

  • Java

    13828questions

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

  • オブジェクト指向

    284questions

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