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

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

ただいまの
回答率

90.35%

  • Java

    14359questions

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

  • if

    219questions

    if文とは様々なプログラミング言語で使用される制御構文の一種であり、条件によって処理の流れを制御します。

  • while

    83questions

    Whileは多くの言語で使われるコントロール構造であり、特定の条件が満たされる限り一連の命令を繰り返し実行します。

Javaで3つのランダム数値が被らない方法が知りたい。

解決済

回答 5

投稿

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

peanut_pie

score 7

 前提・実現したいこと

Javaでスロットのようなシステムを開発しています。
Javaを勉強し始め、1か月です。

本題ですが、以下のようなコードを書きました。
配列で3*3でそれぞれランダムで1~9の数値を持ってくるのですが、列ごとに数値が被らないようにチェックするように組みました。
ですが、実行するとたまに表示されず実行が停止します。
どこかでループが抜け出せなくなっているのかと考えましたが、私の頭ではわかりませんでした。

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

メッセージがありません。 実行をすると何も表示されずにいます。おそらく無限ループ中だと思います。

エラーメッセージ

 該当のソースコード

import java.util.Random;

public class Test{
    public static void main(String[] args){
        Random rand = new Random();
        int [][]array;
        array = new int[3][3];
        array[0][0] = rand.nextInt(9)+1;
        array[0][1] = rand.nextInt(9)+1;
        array[0][2] = rand.nextInt(9)+1;
        array[1][0] = rand.nextInt(9)+1;
        array[1][1] = rand.nextInt(9)+1;
        array[1][2] = rand.nextInt(9)+1;
        array[2][0] = rand.nextInt(9)+1;
        array[2][1] = rand.nextInt(9)+1;
        array[2][2] = rand.nextInt(9)+1;

        //チェック
        while(true){
        if(array[0][0] == array[1][0]){
            array[1][0] = rand.nextInt(9);
        }

        if(array[0][0] == array[2][0]){
            array[2][0] = rand.nextInt(9)+1;
        }else if(array[1][0] == array[2][0]){
                array[2][0] = rand.nextInt(9)+1;
            }else{
                break;
            }

        }
        //チェック2列目
        while(true){
        if(array[0][1] == array[1][1]){
            array[1][1] = rand.nextInt(9);
        }

        if(array[0][1] == array[2][1]){
            array[2][1] = rand.nextInt(9)+1;
        }else if(array[1][1] == array[2][1]){
                array[2][1] = rand.nextInt(9)+1;
            }else{
                break;
            }

        }
        //チェック3列目
        while(true){
        if(array[0][2] == array[1][2]){
            array[1][2] = rand.nextInt(9);
        }

        if(array[0][2] == array[2][2]){
            array[2][1] = rand.nextInt(9)+1;
        }else if(array[1][2] == array[2][2]){
                array[2][2] = rand.nextInt(9)+1;
            }else{
                break;
            }

        }

    }    
                System.out.println((array[0][0])+" "+(array[0][1])+" "+(array[0][2]));
                System.out.println((array[1][0])+" "+(array[1][1])+" "+(array[1][2]));
                System.out.println((array[2][0])+" "+(array[2][1])+" "+(array[2][2]));

    }

 試したこと

while文の内容をすべて書き換えて別の方法でチェックする方法を模索しましたが、私の知力では無理でした。

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

ここにより詳細な情報を記載してください。

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

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

回答 5

checkベストアンサー

+2

        //チェック3列目
        while(true){
            if(array[0][2] == array[1][2]){
                array[1][2] = rand.nextInt(9);
            }
            if(array[0][2] == array[2][2]){
                array[2][1] = rand.nextInt(9)+1;  //ここ
            }else if(array[1][2] == array[2][2]){
                array[2][2] = rand.nextInt(9)+1;
            }else{
                break;
            }

        }


いじっている場所がおかしいため、ここにはまると永遠に抜け出せない

効率よくやるなら、内容の候補をあらかじめ配列などに用意しておき、シャッフルして先頭のいくつかを取って入れればいい。簡単なのはListを使って、Collections.shuffleを使うこと。

    public static void main(String[] args){
        Random rand = new Random();
        int [][]array;
        array = new int[3][3];
        List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9);
        for (int i = 0; i < 3; i++) {
            Collections.shuffle(list);
            for (int j = 0; j < 3; j++) {
                array[j][i] = list.get(j);
            }
        }
    }

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2018/04/24 12:59

    現状コードの間違いを指摘、ということで+1させていただきました。
    あと無限ループの原因ではないですが rand.nextInt(9) になっているところがありますね。(各列最初のif文の中)

    キャンセル

  • 2018/04/24 21:14

    参考にさせていただきました!様々な書き方があることを理解しました。ありがとうございます。

    キャンセル

0

まあ 3x3 ででもすべてかぶらせなくするなら無限ループなんて無用ですね。

/* package whatever; // don't place package name! */

import java.util.*;
import java.lang.*;
import java.io.*;
import java.util.stream.*;

/* Name of the class has to be "Main" only if the class is public. */
class Ideone
{
    public static void main(String[] args) {
        // List<Integer> list = IntStream.rangeClosed(1, 9).mapToObj(Integer::valueOf).collect(Collectors.toList());
        List<Integer> list = IntStream.rangeClosed(1, 9).boxed().collect(Collectors.toList());
        Random r = new Random();
        int[][] matrix = new int[3][3];
        for (int i = 0; i < 3; i++) {
            for (int j = 0; j < 3; j++) {
                Integer value = list.get(r.nextInt(list.size()));
                list.remove(value);
                matrix[i][j] = value.intValue();
            }
        }

        for (int i = 0; i < 3; i++) {
            for (int j = 0; j < 3; j++) {
                System.out.printf("%2d", matrix[i][j]);
            }
            System.out.println();
        }

    }
}

投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2018/04/24 00:56

    1. IntStream#boxed()というメソッドがありまして…
    2. Collectors.toList()で作ったListは変更可能性が保証されていないからremoveは避けたほうがいいのでは

    キャンセル

  • 2018/04/24 06:05

    全体でユニークだとスロットとしては当たりがなくなってしまうのでは?

    キャンセル

  • 2018/04/24 06:26 編集

    Java 1.8 において Collectors.toList() は ArrayList を作成するメソッドではありますけどね

    http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/8-b132/java/util/stream/Collectors.java#Collectors.toList%28%29

    キャンセル

  • 2018/04/24 06:33

    boxed 。。。 あまり使わないから忘れていた・・・サンクス

    キャンセル

  • 2018/04/24 21:11

    javadocには、「可変性を保証しない。toCollection使え」と明記されているみたいですね
    https://docs.oracle.com/javase/jp/8/docs/api/java/util/stream/Collectors.html#toList--

    キャンセル

0

... おそらく無限ループ ...

はい、そうだと思います。
でも、質問文のコードはインデントが変で、構造がよくわかりません。

書き換えてみました。
===> これは間違ってました。 この後に修正したものをかきます。

import java.util.Random;

public class TextXX {
    public static void main(String[] args) {
        int[][] array = new int[3][3];
        Random rand = new Random();
        for (int x = 0; x < 3; x++) {
            for (int y = 0; y < 3; y++) {
                int n;

                // 重ならない数を求める
                while (true) {
                    boolean check = true;
                    n = rand.nextInt(9) + 1;
                    for (int i = 0; i < y - 1; i++) {
                        if (n == array[i][y]) {
                            check = false;
                            break;
                        }
                    }
                    if (check == true) {
                        break;
                    }
                }
                array[x][y] = n;
            }
        }
        // 表示
        for (int x = 0; x < 3; x++) {
            for (int y = 0; y < 3; y++) {
                System.out.print(array[x][y]);
                if (y != 2) {
                    System.out.print(" ");
                }
            }
            System.out.println();
        }
    }
}

数字を植めてからチェック・修正するのでははく、
重ならない数を求めながら順々に埋めて行くようにしています。
結果の表示部分はもっと短く書く方法はありますが、2重の for ループで書いてます。
(java array join で googke 検索すると いろいろな書き方がみつかります)

または
What's the simplest way to print a Java array?
https://stackoverflow.com/questions/409784

追記:
サイズを 9 にしてはしらたら、列に数字が重なってました。
修正をしてみました。

import java.util.Random;

public class TextXX {
    final static int N = 9; // 3

    public static void main(String[] args) {
        int[][] array = new int[N][N];
        Random rand = new Random();
        for (int y = 0; y < N; y++) {
            for (int x = 0; x < N; x++) {
                int n;

                // 重ならない数を求める
                while (true) {
                    boolean check = true;
                    n = rand.nextInt(9) + 1;
                    for (int i = 0; i < y; i++) {
                        if (n == array[x][i]) {
                            check = false;
                            break;
                        }
                    }
                    if (check == true) {
                        break;
                    }
                }
                array[x][y] = n;
            }
        }
        // 表示
        for (int y = 0; y < N; y++) {
            for (int x = 0; x < N; x++) {
                System.out.print(array[x][y]);
                if (x != N -1) {
                    System.out.print(" ");
                }
            }
            System.out.println();
        }
    }
}


実行例
イメージ説明

投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2018/04/24 06:31

    このままだと重複することがあります。一番内側のforループは`for (int i = 0; i < x; i++)`ですね。

    キャンセル

  • 2018/04/24 16:52

    そこじゃなくて、その下の比較式が if (n == array[x][i]) { じゃないかな。

    キャンセル

0

こんにちは、

1.最終的に表示したい数字を格納する2次配列arrayとcountという配列を準備します。
このcountという配列は1~9の数字が最初は1個ずつあり、使うと0になる
それを記憶する配列です。つまり初期化ですべて1にします。
これをメソッドInit()に記述します。

2.ここからが重要なところです。
2重for文でarrayにそれぞれ乱数を格納するとき重複を避けるため
do~while文を使います。
(i)count配列のi番目が0でなければその乱数が格納され 使われた乱数のcountは0になります。
(ii)count配列のi番目が0ならばすでに使われたということなのでdo~while文でまだ使われていない
乱数が出るまでループします。
(iii)一つの列の格納が終わったら、メソッドInit()で初期化します。

3.あとは1~9の乱数が格納されたarrayを2重for文で表示すれば完了です。

import java.util.Random;

public class Main{
    public static void main(String[] args){
        Random rand = new Random();
        int [][]array = new int[3][3];
        int []count = new int[9];
        Init(count);

        for(int i = 0; i < 3; i++){
            Init(count);
            for(int j = 0; j < 3; j++){
                do{
                    array[i][j] = rand.nextInt(9) + 1;
                }while(count[array[i][j] - 1] == 0);
                count[array[i][j] - 1]--;
            }
        }
        for(int i = 0; i < 3; i++){
            for(int j = 0; j < 3; j++){
                System.out.print(array[i][j] + " ");
            }
            System.out.println();
        }
    }    
    public static void Init(int[] count){
        for(int i = 0; i < count.length; i++){
            count[i] = 1;
        }
    }
}

<表示結果の例>
9 5 2 
5 1 3 
7 8 1 

投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2018/04/24 08:36

    表示したい数字は1~9に対して配列の番号は0からなので1ずれるところに注意してください。

    キャンセル

  • 2018/04/24 12:45

    問題は「Javaで3つのランダム数値が被らない方法が知りたい。」で「列ごとに数値が被らないようにチェックする」ということです。「9つのランダム数値が被らない」ではありません。

    キャンセル

  • 2018/04/24 19:18

    回答を訂正しました。

    キャンセル

-1

Javaなど不要。そう、シェル芸ならね!

$ gshuf -i1-9|xargs -n3
8 7 1
6 2 4
3 5 9

追記
列ごとの重複のみ禁止

$ s(){ gshuf -i1-9;};paste -d' ' <(s) <(s) <(s)|head -3
2 8 2
9 7 5
5 1 3

投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2018/04/24 16:12

    列ごとに重複なしにしてスロットのリールにしたいのでは?

    キャンセル

  • 2018/04/24 16:42

    追記しました。

    キャンセル

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

  • Java

    14359questions

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

  • if

    219questions

    if文とは様々なプログラミング言語で使用される制御構文の一種であり、条件によって処理の流れを制御します。

  • while

    83questions

    Whileは多くの言語で使われるコントロール構造であり、特定の条件が満たされる限り一連の命令を繰り返し実行します。