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

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

ただいまの
回答率

90.12%

七並べプログラムを拡張して、 テーブルに置けるカードの候補を表示して、

解決済

回答 1

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 1,361

gyro16

score 83

前提・実現したいこと

七並べプログラムを拡張して、

テーブルに置けるカードの候補を表示して、

キーボードから入力して、そのカードをテーブルに置きたいのですが、

FantanRuleクラスを改変して、その後の利用しているところのFantanPlayerの処理を変えるのですが、

自分でいじったSelectFantanRule では NullPointerException が発生してしまいます

FantanRule と FantanPlayer を拡張して対処したいです。

public class FantanRule implements Rule{
/**

  • テーブルに置けるカードを探す。
  •  
  • @param hand 手札
  • @param table テーブル
  • @return 見つかったカードの組み合わせ。見つからなかった場合はnullを返す
    */
    public Card[] findCandidate(Hand hand, Table table){

// 現在の手札からテーブルに出させるものを探す
Card[] candidate = rule_.findCandidate(myHand_, table_);

// 候補がある場合はテーブルに出す
if(candidate != null){
System.out.println(" " + candidate[0] + "を置きました。\n");
table_.putCard(candidate);

// テーブルの状態を表示する
System.out.println(table_);

// 手札がなくなったら、上がりを宣言する
if(myHand_.getNumberOfCards() == 0){
master_.declareWin(this);
}
} else{
// テーブルに出せるカードがなかった場合、パスする
pass_++;

構成
trump フレームワーク
Card
Hand
Joker
Master
Player
Rule
Table

Fantan
FantanMaster
FantanPlayer
FantanTable
FantanRule

追加拡張に
SelectFantanRule
SelectFantanPlayer
を作っています

発生している問題・エラーメッセージ

NullPointerException がSelectFantanRule のこの辺りで発生していますが、フレームワークのtrump で提供されるCardクラス や Handクラスもいじってはいないので NullPointerException の覚えはないです。

int number = lookingCard.getNumber();
この行を指していますが、Cardクラス も Handクラスもいじってはないので、
この行がNullPointerException と言われています
int number = lookingCard.getNumber();

import trump.Card;
import trump.Table;
import trump.Hand;
import trump.Rule;
import java.util.*;

/*
* 七並べ用ルールクラス。
*/
public class SelectFantanRule implements Rule{
    /**
    * テーブルに置けるカードを探す。
    *
    * @param hand 手札
    * @param table テーブル
    * @return 見つかったカードの組み合わせ。見つからなかった場合はnullを返す
    */
    public Card[] findCandidate(Hand hand, Table table){
        // テーブルに置けるカードの候補
        Card[] candidate = null;
        int count = 0;
        ArrayList<Card> can = null;

        // 手札にあるカードを1枚ずつチェックして、テーブルに置けるか調べる
        int numberOfHand = hand.getNumberOfCards();
        for(int position = 0; position < numberOfHand; position++){
            // 手札にあるカードを見る
            Card lookingCard = hand.lookCard(position);
            int number = lookingCard.getNumber();
            int suit = lookingCard.getSuit();

            // 今注目している手札の左か右にカードがあれば、カードを置ける
            int leftNumber = (number != 1) ? number - 1 : Card.CARD_NUM;
            int rightNumber = (number != Card.CARD_NUM) ? number + 1 : 1;

            if((true == isThereCard(table, suit, leftNumber))
                || (true == isThereCard(table, suit, rightNumber))){
                // 手札からカードを引いて候補とする
                if(count == 0){
                    can = new ArrayList<Card>();
                }
                can.add(hand.pickCard(position));

                /*
                candidate = new Card[1];
                candidate[0] = hand.pickCard(position);
                break;
                */
            }
        }
        if(can.size() != 0){
            candidate = (Card[])can.toArray(new Card[0]);
        }
        return candidate;
    }

    /**
    * テーブルにカードが置かれているか調べる。
    *
    * @param table テーブル
    * @param suit スート
    * @param number 数
    * @return カードが置かれている場合はtrue
    */
    private boolean isThereCard(Table table, int suit, int number){
        // テーブルにあるカードを調べ、カードが置かれているか調べる
        Card[][] cards = table.getCards();
        if(cards[suit - 1][number - 1] != null){
            return true;
        } else{
            return false;
        }
    }
}

import trump.Card;
import trump.Master;
import trump.Table;
import trump.Player;
import trump.Rule;
import java.util.*;

/**
* 七並べ用プレイヤークラス。
*/
public class SelectFantanPlayer extends FantanPlayer{
    /** パスした回数 */
    private int pass_;

    /**
    * コンストラクタ。
    *
    * @param name 名前
    * @param master 進行役
    * @param table テーブル
    * @param rule ルール
    */
    public SelectFantanPlayer(String name, Master master, Table table, Rule rule){
        super(name, master, table, rule);
    }

    /**
    * カードを配る。
    *
    * @param card 受け取ったカード
    */
    public void receiveCard(Card card){
        if(card.getNumber() == 7){
            // カードが7の場合、テーブルにカードを置く
            System.out.println(name_ + ":" + card + "を置きました。");
            table_.putCard(new Card[] { card }); // ()の内側は{}、Card[](card)、配列Card[]をインスタンス化するのに
                                                // new Card[] { 初期化子 } という配列のための記法
        } else{
            // カードが7でない場合は、受け取ったカードを手札へ加える
            super.receiveCard(card);
        }
    }

    /**
    * 順番を指名する。
    *
    * @param nextPlayer 次のプレイヤー
    */
    public void play(Player nextPlayer){
        // 現在の手札を表示する
        System.out.println(" " + myHand_);

        // 現在の手札からテーブルに出させるものを探す
        Card[] candidate = rule_.findCandidate(myHand_, table_);

        // 候補がある場合はテーブルに出す
        if(candidate != null){
            System.out.println("テーブルに置けるカードは:");
            for(int i = 0; i < candidate.length; i++){
                if(i != candidate.length - 1){
                    System.out.print(candidate[i] + ",");
                }else{
                    System.out.println(candidate[i] + ":");
                }
            }
            Scanner scan = new Scanner(System.in);
            System.out.println("テーブルに置くカードを入力してください");
            String input = scan.next();
            for(int i = 0; i < candidate.length; i++){
                if(input.equals(candidate[i].toString())){
                    Card[] card = new Card[1];
                    card[0] = candidate[i];
                    table_.putCard(card);
                    System.out.println(" " + card[0] + "を置きました。\n");

                    // テーブルの状態を表示する
                    System.out.println(table_);
                    // 手札がなくなったら、上がりを宣言する
                    if(myHand_.getNumberOfCards() == 0){
                        master_.declareWin(this);
                    }
                }
            }

            /*
            System.out.println(" " + candidate[0] + "を置きました。\n");
            table_.putCard(candidate);

            // テーブルの状態を表示する
            System.out.println(table_);

            // 手札がなくなったら、上がりを宣言する
            if(myHand_.getNumberOfCards() == 0){
                master_.declareWin(this);
            }
            */
        } else{
            // テーブルに出せるカードがなかった場合、パスする
            pass_++;
            ((FantanMaster)master_).pass(this); // (FantanMaster)キャストが必要、FantanMaster固有の処理

            // パス回数が制限回数以上ならばカードを全てテーブルに置く
            if(pass_ > FantanMaster.PASS_LIMIT){
                int numberOfHand = myHand_.getNumberOfCards();
                // 手札を全てテーブルに置く
                for(int count = 0; count < numberOfHand; count++){
                    table_.putCard(new Card[] { myHand_.pickCard(0) }); // 手札の枚数の数だけ1枚ずつカードを引いて置く
                                                                        // putCard()はCard[]配列
                                                                        // new Card[] { 初期化子 } という配列のための記法
                }
            }
        }
    }

    /**
    * パスした回数を教える。
    *
    * @return パスした回数
    */
    public int getPass(){
        return pass_;
    }
}


こちらが元の七並べプログラムです。
テーブルに置ける、最初に見つけた候補のカードをただ置くだけのプログラムです。

該当のソースコード

import trump.Card;
import trump.Table;
import trump.Hand;
import trump.Rule;

/*
* 七並べ用ルールクラス。
*/
public class FantanRule implements Rule{
    /**
    * テーブルに置けるカードを探す。
    *
    * @param hand 手札
    * @param table テーブル
    * @return 見つかったカードの組み合わせ。見つからなかった場合はnullを返す
    */
    public Card[] findCandidate(Hand hand, Table table){
        // テーブルに置けるカードの候補
        Card[] candidate = null;

        // 手札にあるカードを1枚ずつチェックして、テーブルに置けるか調べる
        int numberOfHand = hand.getNumberOfCards();
        for(int position = 0; position < numberOfHand; position++){
            // 手札にあるカードを見る
            Card lookingCard = hand.lookCard(position);
            int number = lookingCard.getNumber();
            int suit = lookingCard.getSuit();

            // 今注目している手札の左か右にカードがあれば、カードを置ける
            int leftNumber = (number != 1) ? number - 1 : Card.CARD_NUM;
            int rightNumber = (number != Card.CARD_NUM) ? number + 1 : 1;

            if((true == isThereCard(table, suit, leftNumber))
                || (true == isThereCard(table, suit, rightNumber))){
                // 手札からカードを引いて候補とする
                candidate = new Card[1];
                candidate[0] = hand.pickCard(position);
                break;
            }
        }
        return candidate;
    }

    /**
    * テーブルにカードが置かれているか調べる。
    *
    * @param table テーブル
    * @param suit スート
    * @param number 数
    * @return カードが置かれている場合はtrue
    */
    private boolean isThereCard(Table table, int suit, int number){
        // テーブルにあるカードを調べ、カードが置かれているか調べる
        Card[][] cards = table.getCards();
        if(cards[suit - 1][number - 1] != null){
            return true;
        } else{
            return false;
        }
    }
}

試したこと

SelectFantanRule 、SelectPlayer を作ってみたがうまくいかない

補足情報(言語/FW/ツール等のバージョンなど)

より詳細な情報

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

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

質問への追記・修正、ベストアンサー選択の依頼

  • swordone

    2017/01/27 14:43

    「丸投げです」などのコメントはteratailが出している訳ではなく、他のユーザが質問に対して「低評価」のボタンを押して、その理由を選ぶことで出てきます。まあこれは丸投げとは私は思わないので、誰か悪意で、もしくは質問をちゃんと読まずに付けているのではないでしょうか。

    キャンセル

  • swordone

    2017/01/27 14:47

    ただ、スタックトレースを載せてくれとお願いしたはずですが…。加えて、あなたがフレームワークで使っているというtrumpパッケージの各クラスがどういうものなのかわからないので、そのコード、あるいはドキュメントを提示してください。

    キャンセル

  • gyro16

    2017/01/27 15:28

    ソースを載せたいのですが、勝手が変わってページに全部載りません。

    キャンセル

回答 1

check解決した方法

0

can.add(hand.pickCard(position));
ではなくて、
can.add(lookingCard);
です。
pickCard()はカードを引き出して、手札から削除していました。pickCard()は抜き取るメソッドでした。
候補を見るだけなら条件を満たしたカードを見るだけですので、条件を満たしたlookingCardです。
メソッドの使い方を誤解していたため抜き取ってしまったため NullPointerExceptionが発生していました。

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2017/01/27 20:55

    お陰様で今日は2本のプログラムが完成したしました。
    少しづつ力はついています。有難うございました。

    キャンセル

  • 2017/01/27 23:13

    これではクラスの内容がわからないわれわれには回答しようのない質問でしたね。
    だからドキュメントの提示をお願いしたのですが、伝わらなかったようですね。

    キャンセル

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

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