【Java】魔方陣「ミニナンプレ」の完成表を出力するプログラム

javaでミニナンプレを作るプログラミング制作物
プログラミング制作物

今回は、前回『【Java】ランダムな4×4の魔方陣をプログラミングで作ってみる』の記事で作成したものとは違うタイプである魔方陣をJavaで、そこから「ミニナンプレ」を作ってみます。

この記事は「ミニナンプレの完成表を出力するプログラムを作るところ」までやります。

この記事に書いてあること
  • ミニナンプレについての説明
  • ミニナンプレの完成表を出力するプログラムの作成
スポンサーリンク

ミニナンプレとは

ナンプレ」はロジックパズルとして有名で馴染み深いものとして知られています。今回作る「ミニナンプレ」はナンプレを簡略化したもので、「1~4の数字」を使った4×4のパズルです。下に、問題と解答の一例を画像で示します。

ミニナンプレ
ミニナンプレの一例

画像のように、「縦と横の全ての列」と「中心で区切られた4マスのボックス」に1~4の数字が全て入るように数字を当てはめます。

今回のプログラムを作成について、まず画像右側の完成した表から作っていき、そこから左側の問題となる表を求めたいと思います。

4×4のミニナンプレ表(完成表)を作成する

前回の記事で書いたプログラムを改変して使います。アルゴリズムとしては以下のような流れになります。

アルゴリズム
  1. ArrayListで1~4が格納された配列listを作り、shuffleメソッドでシャッフルする それを4×4の配列numに4回分のlistを格納して仮の表を作る
  2. 仮表が条件に一致するまでその都度シャッフルを繰り返す
  3. 条件に一致した仮表が出来たら完成表として出力する

アルゴリズムの詳細な部分は前回と被るところが多いので割愛します。気になる方は、上にある前回の記事のリンク(こちら)からご覧ください。

前回の魔方陣の時と違うところは、「全ての行・列・ボックスの合計が10である」「横の行については既にシャッフルによって完成しているので、縦の列とボックスのみ比較すれば良い」の2点です。縦の行とボックスはHashSetを使って重複してない数字をintegerSetに入れ、sizeメソッドを使ってsizeが4(1から4全て使ってる)かチェックしました。

なお、ボックスの比較については、縦横が揃っていてボックスの4つの内どれか一つっでも条件を満たしていれば他の3つも自動的に条件を満たすため、左上のみ判定しています。また、前回と同様シャッフル回数測定のためにcountを設置しています。

実際にできたコードが下になります。

サンプルコードと出力結果

サンプルコードを以下に示します。

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;

public class Mahou4_2 {

	public static void main(String[] args) {
		ArrayList<Integer> list = new ArrayList<Integer>();
		Set<Integer> integerSet = new HashSet<>();
		int i = 0, j = 0, x = 0, count = 0;
		int[][] num = new int[4][4];

        //listに1~4までを入れる
		for (i = 1; i <= 4; i++) {
			list.add(i);
		}

		while (x < 1) {

            //シャッフルしnum[4][4]にlistの中身を格納×4
			Collections.shuffle(list);
			count++;			
			for (i = 0; i <= 3; i++) {
				for (j = 0; j <= 3; j++) {
					num[i][j] = list.get(j);
				}
				Collections.shuffle(list);
				count++;			
			}

            //縦の列を比較
			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++;

                //縦の列はOKなのでボックスの中身を比較する
                //左上のボックスが条件を満たしていれば他のボックスも自動的にOK
				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();
			}
		}

        //完成表が得られたので出力する
		for (i = 0; i < 4; i++) {
			for (j = 0; j < 4; j++) {
				System.out.printf("%3d", num[i][j]);
			}
			System.out.println();
		}
		System.out.println(count);
	}
}

サンプルコードの実行結果を以下に示します。ランダム性があるので結果は一例です。

  2  4  1  3
  3  1  2  4
  1  3  4  2
  4  2  3  1
7175 //count回数

完成表が出力されました。countは7000ちょっとでした。前回よりシャッフル回数も格段に少ないことが分かります。こちらの方が存在するパターンが多いので、完成表を求めるのに試行回数が少なく済んでいます。

次の「②の記事」では、今回得た表からどうやってミニナンプレを作るか検討していきます。以上で記事を終わりにします。

スポンサーリンク
Dim雑記
タイトルとURLをコピーしました