Dimです。前回の『Java|魔方陣「ミニナンプレ」を解くプログラムを作る』の続きになります。
今回は完成表からランダムに穴を開けるプログラムの作成と、これまでの3つのプログラムを組み合わせてミニナンプレを作るプログラムを完成させたいと思います。
完成表からランダムに穴を開けるプログラムを作る
まず、以下の様な完成表から、ランダムに0に置き換えることでミニナンプレの問題を作ります。
今回は16個ある数字の内10個を0に置き換えてみることにします。
1 2 3 4 3 4 1 2 4 3 2 1 2 1 4 3 ↓ 1 0 0 0 3 0 1 2 0 0 0 0 0 1 4 0
上に与えられた完成表から10個の要素をランダムで0に置き換えるプログラムコードを書いていきます。
どこを0に置き換えるかを決めるには、0~15まで入ったArrayListを作り、shuffleメソッドでシャッフルして上から6個の要素の数字はそのままで、それ以外は0を代入しました。
サンプルコードと出力結果
サンプルコードを以下に示します。
import java.util.ArrayList; import java.util.Collections; public class Mahou4_hole { public static void main(String[] args) { int[][] num1 = { { 1, 2, 3, 4 }, { 3, 4, 1, 2 }, { 4, 3, 2, 1 }, { 2, 1, 4, 3 } }; int[][] num2 = new int[4][4]; ArrayList<Integer> list = new ArrayList<Integer>(); int i; // 0に置き換える箇所を決める for (i = 0; i <= 15; i++) { list.add(i); } Collections.shuffle(list); // 完成表から要素に0を代入していく int j, x = 0; for (i = 0; i < 4; i++) { for (j = 0; j < 4; j++) { if (x == list.get(0) || x == list.get(1) || x == list.get(2) || x == list.get(3) || x == list.get(4) || x == list.get(5)) { num2[i][j] = num1[i][j]; } else { num2[i][j] = 0; } x++; } } // 完成表を出力する for (i = 0; i < 4; i++) { for (j = 0; j < 4; j++) { System.out.printf("%3d", num1[i][j]); } System.out.println(); } System.out.println(); // 問題表を出力する for (i = 0; i < 4; i++) { for (j = 0; j < 4; j++) { System.out.printf("%3d", num2[i][j]); } System.out.println(); } } }
サンプルコードの出力結果を以下に示します。ランダム性があるので結果は一例です。
1 2 3 4 3 4 1 2 4 3 2 1 2 1 4 3 0 0 0 4 0 4 0 0 4 0 2 0 2 0 0 3
ランダムに0が挿入されました。
3つのコードを組み合わせて完成させる
それでは今までの記事のコードを組み合わせて「ミニナンプレ」の問題を作るプログラムを完成させます。
サンプルコードと出力結果
サンプルコードを以下に示します。
import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.HashSet; import java.util.Random; import java.util.Set; public class Mahou_mininanpure { public static int[][] mahou_make() { ArrayList<Integer> list = new ArrayList<Integer>(); Set<Integer> integerSet = new HashSet<>(); int i = 0, j = 0, x = 0; int[][] num = new int[4][4]; for (i = 1; i <= 4; i++) { list.add(i); } while (x < 1) { Collections.shuffle(list); for (i = 0; i <= 3; i++) { for (j = 0; j <= 3; j++) { num[i][j] = list.get(j); } Collections.shuffle(list); } for (i = 0; i <= 3;) { for (j = 0; j <= 3; j++) { integerSet.add(num[j][i]); } if (integerSet.size() != 4) { integerSet.clear(); i = 0; break; } integerSet.clear(); i++; if (i == 4) { integerSet.add(num[0][0]); integerSet.add(num[0][1]); integerSet.add(num[1][0]); integerSet.add(num[1][1]); if (integerSet.size() == 4) { x++; } } integerSet.clear(); } } return num; } public static int[][] mahou_hole(int num_kansei[][]) { int[][] num = new int[4][4]; ArrayList<Integer> list = new ArrayList<Integer>(); int i; for (i = 0; i <= 15; i++) { list.add(i); } Collections.shuffle(list); int j, x = 0; for (i = 0; i < 4; i++) { for (j = 0; j < 4; j++) { if (x == list.get(0) || x == list.get(1) || x == list.get(2) || x == list.get(3) || x == list.get(4) || x == list.get(5)) { num[i][j] = num_kansei[i][j]; } else { num[i][j] = 0; } x++; } } return num; } public static boolean mahou_check(int num1, int num2, int num3, int num4, int rnd) { Set<Integer> integerSet = new HashSet<>(); integerSet.add(num1); integerSet.add(num2); integerSet.add(num3); integerSet.add(num4); if (integerSet.contains(rnd)) { integerSet.clear(); return true; } else { integerSet.clear(); return false; } } public static int[][] mahou_test(int num_mondai[][]) { int[][] num2 = new int[4][4]; int i = 0, j = 0, rnd, x = 0, count = 0; Random rand = new Random(); while (x < 1) { for (i = 0; i <= 3;) { for (j = 0; j <= 3;) { if (num_mondai[i][j] != 0) { num2[i][j] = num_mondai[i][j]; j++; } else { rnd = rand.nextInt(4) + 1; if (mahou_check(num2[i][0], num2[i][1], num2[i][2], num2[i][3], rnd)) { count++; if (count > 100) { i = 0; j = 0; num2 = new int[4][4]; count = 0; break; } } else { if (mahou_check(num2[0][j], num2[1][j], num2[2][j], num2[3][j], rnd)) { count++; if (count > 100) { i = 0; j = 0; num2 = new int[4][4]; count = 0; break; } } else { num2[i][j] = rnd; j++; } } } } if (j > 3) { i++; } } int box1 = num2[0][0] + num2[0][1] + num2[1][0] + num2[1][1]; int box2 = num2[0][2] + num2[0][3] + num2[1][2] + num2[1][3]; int box3 = num2[2][0] + num2[2][1] + num2[3][0] + num2[3][1]; int box4 = num2[2][2] + num2[2][3] + num2[3][2] + num2[3][3]; if (box1 == 10 && box2 == 10 && box3 == 10 && box4 == 10) { x++; } else { i = 0; j = 0; num2 = new int[4][4]; } } return num2; } public static void main(String[] args) { int num_kansei[][] = mahou_make(); int num_mondai[][] = mahou_hole(num_kansei); int i, j; System.out.println("完成表"); for (i = 0; i < 4; i++) { for (j = 0; j < 4; j++) { System.out.printf("%3d", num_kansei[i][j]); } System.out.println(); } System.out.println("問題表"); for (i = 0; i < 4; i++) { for (j = 0; j < 4; j++) { System.out.printf("%3d", num_mondai[i][j]); } System.out.println(); } int num_test[][] = mahou_test(num_mondai); if (Arrays.deepEquals(num_kansei, num_test)) { } else { System.out.println("別解"); for (i = 0; i < 4; i++) { for (j = 0; j < 4; j++) { System.out.printf("%3d", num_test[i][j]); } System.out.println(); } } } }
サンプルコードの出力結果を以下に示します。結果は一例です。
完成表 3 4 2 1 2 1 4 3 4 3 1 2 1 2 3 4 問題表 3 0 0 1 0 0 0 3 0 3 0 2 0 0 3 0 別解 3 2 4 1 1 4 2 3 4 3 1 2 2 1 3 4
一応別解を見つけた場合は出力することにしてみましたが、別解が2つ以上ある時には対応してません…。
作ってみた感想
とりあえずナンプレを作ることには成功できたので良かったです!
ただコードが長くなってしまったので、もっとスマートにしてみたいですね。