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

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

新規登録して質問してみよう
ただいま回答率
85.48%
if

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

Java

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

while

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

Q&A

解決済

5回答

3305閲覧

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

peanut_pie

総合スコア13

if

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

Java

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

while

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

0グッド

1クリップ

投稿2018/04/23 14:38

前提・実現したいこと

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

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

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

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

エラーメッセージ

該当のソースコード

Java

1import java.util.Random; 2 3public class Test{ 4 public static void main(String[] args){ 5 Random rand = new Random(); 6 int [][]array; 7 array = new int[3][3]; 8 array[0][0] = rand.nextInt(9)+1; 9 array[0][1] = rand.nextInt(9)+1; 10 array[0][2] = rand.nextInt(9)+1; 11 array[1][0] = rand.nextInt(9)+1; 12 array[1][1] = rand.nextInt(9)+1; 13 array[1][2] = rand.nextInt(9)+1; 14 array[2][0] = rand.nextInt(9)+1; 15 array[2][1] = rand.nextInt(9)+1; 16 array[2][2] = rand.nextInt(9)+1; 17 18 //チェック 19 while(true){ 20 if(array[0][0] == array[1][0]){ 21 array[1][0] = rand.nextInt(9); 22 } 23 24 if(array[0][0] == array[2][0]){ 25 array[2][0] = rand.nextInt(9)+1; 26 }else if(array[1][0] == array[2][0]){ 27 array[2][0] = rand.nextInt(9)+1; 28 }else{ 29 break; 30 } 31 32 } 33 //チェック2列目 34 while(true){ 35 if(array[0][1] == array[1][1]){ 36 array[1][1] = rand.nextInt(9); 37 } 38 39 if(array[0][1] == array[2][1]){ 40 array[2][1] = rand.nextInt(9)+1; 41 }else if(array[1][1] == array[2][1]){ 42 array[2][1] = rand.nextInt(9)+1; 43 }else{ 44 break; 45 } 46 47 } 48 //チェック3列目 49 while(true){ 50 if(array[0][2] == array[1][2]){ 51 array[1][2] = rand.nextInt(9); 52 } 53 54 if(array[0][2] == array[2][2]){ 55 array[2][1] = rand.nextInt(9)+1; 56 }else if(array[1][2] == array[2][2]){ 57 array[2][2] = rand.nextInt(9)+1; 58 }else{ 59 break; 60 } 61 62 } 63 64 } 65 System.out.println((array[0][0])+" "+(array[0][1])+" "+(array[0][2])); 66 System.out.println((array[1][0])+" "+(array[1][1])+" "+(array[1][2])); 67 System.out.println((array[2][0])+" "+(array[2][1])+" "+(array[2][2])); 68 69 } 70

試したこと

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

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

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

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

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

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

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答5

0

ベストアンサー

java

1 //チェック3列目 2 while(true){ 3 if(array[0][2] == array[1][2]){ 4 array[1][2] = rand.nextInt(9); 5 } 6 if(array[0][2] == array[2][2]){ 7 array[2][1] = rand.nextInt(9)+1; //ここ 8 }else if(array[1][2] == array[2][2]){ 9 array[2][2] = rand.nextInt(9)+1; 10 }else{ 11 break; 12 } 13 14 }

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

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

java

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

投稿2018/04/23 15:11

swordone

総合スコア20651

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

fuzzball

2018/04/24 03:59

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

2018/04/24 12:14

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

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文で表示すれば完了です。

Java

1import java.util.Random; 2 3public class Main{ 4 public static void main(String[] args){ 5 Random rand = new Random(); 6 int [][]array = new int[3][3]; 7 int []count = new int[9]; 8 Init(count); 9 10 for(int i = 0; i < 3; i++){ 11 Init(count); 12 for(int j = 0; j < 3; j++){ 13 do{ 14 array[i][j] = rand.nextInt(9) + 1; 15 }while(count[array[i][j] - 1] == 0); 16 count[array[i][j] - 1]--; 17 } 18 } 19 for(int i = 0; i < 3; i++){ 20 for(int j = 0; j < 3; j++){ 21 System.out.print(array[i][j] + " "); 22 } 23 System.out.println(); 24 } 25 } 26 public static void Init(int[] count){ 27 for(int i = 0; i < count.length; i++){ 28 count[i] = 1; 29 } 30 } 31}

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

投稿2018/04/23 23:34

編集2018/04/24 10:17
退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2018/04/23 23:36

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

退会済みユーザー

2018/04/24 03:45

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

退会済みユーザー

2018/04/24 10:18

回答を訂正しました。
guest

0

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

bash

1$ gshuf -i1-9|xargs -n3 28 7 1 36 2 4 43 5 9

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

bash

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

投稿2018/04/23 22:30

編集2018/04/24 07:40
hichon

総合スコア5737

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

swordone

2018/04/24 07:12

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

2018/04/24 07:42

追記しました。
guest

0

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

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

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

java

1import java.util.Random; 2 3public class TextXX { 4 public static void main(String[] args) { 5 int[][] array = new int[3][3]; 6 Random rand = new Random(); 7 for (int x = 0; x < 3; x++) { 8 for (int y = 0; y < 3; y++) { 9 int n; 10 11 // 重ならない数を求める 12 while (true) { 13 boolean check = true; 14 n = rand.nextInt(9) + 1; 15 for (int i = 0; i < y - 1; i++) { 16 if (n == array[i][y]) { 17 check = false; 18 break; 19 } 20 } 21 if (check == true) { 22 break; 23 } 24 } 25 array[x][y] = n; 26 } 27 } 28 // 表示 29 for (int x = 0; x < 3; x++) { 30 for (int y = 0; y < 3; y++) { 31 System.out.print(array[x][y]); 32 if (y != 2) { 33 System.out.print(" "); 34 } 35 } 36 System.out.println(); 37 } 38 } 39}

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

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

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

java

1import java.util.Random; 2 3public class TextXX { 4 final static int N = 9; // 3 5 6 public static void main(String[] args) { 7 int[][] array = new int[N][N]; 8 Random rand = new Random(); 9 for (int y = 0; y < N; y++) { 10 for (int x = 0; x < N; x++) { 11 int n; 12 13 // 重ならない数を求める 14 while (true) { 15 boolean check = true; 16 n = rand.nextInt(9) + 1; 17 for (int i = 0; i < y; i++) { 18 if (n == array[x][i]) { 19 check = false; 20 break; 21 } 22 } 23 if (check == true) { 24 break; 25 } 26 } 27 array[x][y] = n; 28 } 29 } 30 // 表示 31 for (int y = 0; y < N; y++) { 32 for (int x = 0; x < N; x++) { 33 System.out.print(array[x][y]); 34 if (x != N -1) { 35 System.out.print(" "); 36 } 37 } 38 System.out.println(); 39 } 40 } 41}

実行例
イメージ説明

投稿2018/04/23 15:56

編集2018/04/24 13:11
katoy

総合スコア22324

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2018/04/23 21:31

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

2018/04/24 07:52

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

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/23 15:53

編集2018/04/23 21:22
退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

swordone

2018/04/23 15:56

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

退会済みユーザー

2018/04/23 21:05

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

退会済みユーザー

2018/04/23 21:33

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問