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

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

ただいまの
回答率

88.22%

NEW Java ブラックジャックを作成しています。

受付中

回答 2

投稿 編集

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

前提・実現したいこと

Javaでブラックジャックを作成しています。
・トランプの絵柄は今回無視しています。
・エースは1と11がありますが、1で固定しています。
ゲームの流れ
・ディーラーがカードを2枚引く
・ディーラーは手札の合計が17以上になるまでカードを引き続ける。
・ユーザーがカードを2枚引く。
・ディーラーは手札の合計が17以上になるまでカードを引き続ける。
・ディーラーとユーザーのスコアを比べる。
・ユーザーのバースト、勝ち、負け、いずれかの結果を発表する。

発生している問題

・ディーラーがバストしたとき、ディーラーがもう一枚カードを引いている。
・ディーラーがバストしたとき、ユーザーはバストしていないのに、負け判定になる。
・ディーラーとユーザーは17以上になるまでカードを引き続けるようにしたいが、3枚目を引いた時点で終了してしまう。(この点は恐らくループ処理を用いるべきだと考えています。)

※初めての質問で大変恐縮ですが、質問の仕方、入力場所等に誤りがあるかもしれませんが、その際は遠慮なくご指摘ください。

package home;
import java.util.ArrayList;
abstract class Human {
    ArrayList<Integer> myCards = new ArrayList<>(); //両プレイヤーの手札の情報


    abstract protected int open(); //手札の合計値を計算
    abstract protected void setCard(ArrayList<Integer>drawnCards); //引いたカードを手札に追加
    abstract protected boolean checkSum(); //まだカードを引くべきか判断する
}
//Human,User,Dealerクラスにおいて、全てのメソッドにpublic,全てのフィールドにprotected.
//ディーラーが3枚引いて終了してしまう.
package home;
import java.util.ArrayList;

public class User extends Human {

    protected int total=0;
    @Override
    public int open() {    //手札の合計値を計算
         int result =0;
        for(int i =0;i<myCards.size();i++) {
            result+= myCards.get(i);
        }
        return result;//戻り値は手札の合計値
    }

    @Override//引いたカードを手札に追加するメソッド
    public void setCard(ArrayList<Integer>drawnCards) {
        myCards.addAll(drawnCards);
    }

    @Override
    public boolean checkSum() {
    if(total<17) {
        return true;
    }else  {
        return false;
        }
    }
}
package home;
import java.util.ArrayList;
import java.util.Collections;

public class Dealer extends Human {
    ArrayList<Integer> cards = new ArrayList<>(); //山札のデッキ
    protected int total=0;
    @Override    //手札の合計値を計算
    public int open() {
        int result =0;
        for(int i =0;i<myCards.size();i++) {
            result+= myCards.get(i);
            }
            return result;//戻り値は手札の合計値
        }
    @Override    //引いたカードを手札に追加するメソッド
    public void setCard(ArrayList<Integer> drawnCards) {
        myCards.addAll(drawnCards);
        }
    @Override
    public boolean checkSum() {
        if(total<=17) {
            return true;
        }else {
            return false;
        }
    }
    //コンストラクタ
    //山札に全カードを追加
    //最後に山札をシャッフル
    public   Dealer() {
        for (int m =1;m<=4;m++) {
            for(int n =1;n<=13;n++) {
                cards.add(n);
            }
        }
        Collections.shuffle(cards);
    }
    //山札から2枚引き、引いたカードを戻り値にする
    //引いたカードを山札からremoveする
    public ArrayList<Integer> deal() {
        ArrayList<Integer> drawnCards = new ArrayList<>();//両プレイヤーの引いたカード//
        drawnCards.add(cards.get(0));
        cards.remove(0);
        drawnCards.add(cards.get(1));
        cards.remove(1);
        return drawnCards;
    }
    //山札から1枚引き、ひいたカードを戻り値とする。
    public ArrayList<Integer> hit() {
        ArrayList<Integer> hit= new ArrayList<>();
        hit.add(cards.get(0));
        cards.remove(0);
        return hit;
    }
}
package home;

public class BlackJack {
    public static void main(String[] args) {
        User user1 = new User();
        Dealer dealer1 = new Dealer();
        System.out.println("ブラックジャックを始めます。");
        user1.setCard(dealer1.deal());
        dealer1.setCard(dealer1.deal());
        System.out.println("ディーラーのカードは"+dealer1.myCards.get(0)+","+dealer1.myCards.get(1)+"です。");
        if(dealer1.checkSum()==true) {
            System.out.println("ディーラーはもう一枚引きます。");
            dealer1.setCard(dealer1.hit());
            System.out.println("ディーラーの引いたカードは"+dealer1.myCards.get(0)+","+dealer1.myCards.get(1)+","+dealer1.myCards.get(2)+"です。");
            System.out.println("ディーラーのスコアは合計で"+dealer1.open()+"です。");
        }else {
            System.out.println("ディーラーのスコアは確定しました。");
        }
        System.out.println("あなたのカードは"+user1.myCards.get(0)+","+user1.myCards.get(1)+"です。");
        if (user1.checkSum()==true) {
            System.out.println("あなたはもう一枚引きます。");
            user1.setCard(dealer1.hit());
        }else {
            System.out.println("あなたのスコアは確定しました。");
        }
        System.out.println("ディーラーの合計スコアは"+dealer1.open()+"です。");
        System.out.println("あなたの合計スコアは"+user1.open()+"です。");
        if(user1.open()>21) {
            System.out.println("あなたはバーストしました。あなたの負けです。");
        }else if (user1.open()>dealer1.open()) {
            System.out.println("あなたの勝ちです。");
        }else {
            System.out.println("あなたの負けです。");
        }
    }
}
ブラックジャックを始めます。
ディーラーのカードは6,12です。
ディーラーはもう一枚引きます。
ディーラーの引いたカードは6,12,9です。
ディーラーのスコアは合計で27です。
あなたのカードは4,13です。
あなたはもう一枚引きます。
ディーラーの合計スコアは27です。
あなたの合計スコアは19です。
あなたの負けです。
  • 気になる質問をクリップする

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

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

  • YamatoKogushi

    2020/04/17 19:04

    ご回答ありがとうございます。コードと質問内容を大幅に変更した理由は、自身が理解できていないままに、質問してしまった点、また、改善点が多すぎてかえって参考にならないと私が判断したことによります。
    teratailの趣旨を確認したところ、「プログラミングに関わる問題を皆で正しあい、切磋琢磨できる環境を作る。」というものでした。
    その観点から、私は別段、趣旨に合わないとは判断していません。また、teratailの推奨していない質問にも該当しないと私は判断しました。
    しかしながら、jimbeさんのおっしゃる通り、何度も変更することは他の方の情報資産にならないので、今後は慎みたいと思います。貴重なご意見ありがとうございます。

    キャンセル

  • m.ts10806

    2020/04/17 20:27

    元の質問を残して追記すれば良かったのでは。
    既に回答やコメントがついている以上、指摘内容の反映ならともかく、大幅改変するときには関わっている人への確認(相談)は不可欠と思います。

    キャンセル

  • jimbe

    2020/04/18 16:18

    > ※初めての質問で大変恐縮ですが ~
    ということでしたが
    > teratailの趣旨を確認
    されたということですので(元よりですが)判断はお任せです.
    失礼しました.

    個人的には, コードの変容は即ち作者である YamatoKogushi さんのプログラミング技術の変化の現れですので, 変容を見てみたくもあり, 失礼な例えですが「二軍の野球選手の話でも(未来のスターの卵たりえる)野球少年の役には立つかもしれない」ような感覚でいます.

    キャンセル

回答 2

0

        b.setCard(b.deal());


まずここの実行を考えます。b.deal()の実行により、b.drawnCardsb.cards.get(0)b.cards.get(1)の結果が追加されます。これが1と13だとすると、b.drawnCardsの中身が[1,13]になります。その結果がsetCardによってb.myCardsに移され、b.myCardsの中身が[1,13]になります。

        a.setCard(b.deal());


次にここの実行を考えます。再びb.deal()が実行されますが、b.drawnCardsの中身はそのまま残っています。すでにあった[1,13]に再び1と13が追加され、b.drawnCardsの中身は[1,13,1,13]となります。setCardによって、これがそっくりそのままa.myCardsに移され、a.myCardsの中身が[1,13,1,13]になります。
その後、○○のカードは~の出力に入りますが、どちらも最初の2枚しか出力しないため、ここでの見た目は変わらないように見えます。この状態で合計を取れば、aの方は同じカードセットを2回分持っているわけですから、当然倍になります。

本題に関係ないですが、「もう一枚引きます」とだけ出力して、実際には何もしていないです。
それを含めて、設計に大いに難ありです。

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2020/04/17 18:04

    remove を追加されましたが,
    > drawnCards.add(cards.get(0));
    > cards.remove(0);
    > drawnCards.add(cards.get(1));
    > cards.remove(1);
    remove(0) した時点でcards の中身は1つ減り, 2枚目だったものが1枚目に, 3枚目だったものが2枚目に...と移動しています.
    その状態で get(1)/remove(1) をしては, その時点で1枚目にあるものを抜かしていることになります.
    ゲームとしてはどちらでも変わらないとは思いますが...

    キャンセル

  • 2020/04/17 19:24

    ご回答ありがとうございます。こちらのご回答が良く理解できていないので、詳細にお教えいただけると幸いです。removeを用いるタイミングが適切でないということでしょうか?

    キャンセル

  • 2020/04/17 20:08

    cards に 52 枚のカード, 分かり易く 1,2,3,4,... が入っているとします.
    get(0), remove(0) で先頭の一枚, "1" が取り出され, 削除されます.
    この時点で, cards には 51 枚のカード 2,3,4,... が残ります.
    もう一枚得るのであれば, また先頭, すなわちもう一度 get(0), remove(0) を行えば "2" が取り出され, cards には 50 枚のカード 3,4,... が残ることになります.

    キャンセル

0

>ディーラーがバストしたとき、ディーラーがもう一枚カードを引いている。

こちら意味が分からないのですが, バーストはもう一枚引いた為に発生するのではないでしょうか. 引かずにバーストはしないと思うのですが.
実行例で 6,12 と合計 18 なのにもう一枚引いているということでしょうか.
checkSum で使用している total 変数が全く計算されていない( 0 のまま)為かと思います.

>ディーラーがバストしたとき、ユーザーはバストしていないのに、負け判定になる。

勝敗判定にディーラーがバーストしている場合という判定( if 文)がありません.

>ディーラーとユーザーは17以上になるまでカードを引き続けるようにしたいが、3枚目を引いた時点で終了してしまう

仰る通り, ループしなければならないでしょう.

なお, 「ディーラーとユーザーは17以上になるまで」とされていますが, コード上では Dealer と User で checkSum が異なっています.
また, checkSum が同じコードとなるのであれば, Dealer/User 双方で checkSum を定義する必要は無く, Human に定義しては如何でしょうか.
(これは現状でも内容が同じ open や setCard にも言えます.)

投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2020/04/17 19:08

    ご回答ありがとうございます。こちらは本来のブラックジャックであれば起こりえないのであまり参考にはならないかもしれませんが、11,12,13をそのままの数字でカウントする仕様になっているので、最初の二枚がそれらだと生じてしまうエラーとなっています。
    他のご指摘に関してはアドバイス通り修正を試みようと思います。
    どうもありがとうございます。

    キャンセル

  • 2020/04/17 20:09 編集

    あぁ、確かに, open は今は 11 以上をそのまま計算しているのでしたね. すいません失念していました.
    でも checkSum の total 変数に値が入っていない点では同じようです.

    キャンセル

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

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

関連した質問

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