【Java】ランダムな4×4の魔方陣をプログラミングで作ってみる

【Java】ランダムな4×4の魔方陣をプログラミングで作ってみる

今回は、Javaを使って4行4列の16マスの魔方陣(1~16の数字を1つずつ使ったもの)をランダムで生成するコードを作成してみたいと思います。

目次

魔方陣の概要

皆さんは「魔方陣」と言われるものをご存知でしょうか?魔方陣とは、以下のような縦・横・斜めの全ての列の合計が同じになる数表のことをいいます。今回は1~16の数字を一つずつ使ったものを作っていきます。下に魔方陣の一例を示します。

$$ \large\begin{array}{|c|c|c|c|} \hline 1 & 14 & 15 & 4 \\ \hline 8 & 11 & 10 & 5 \\ \hline 12 & 7 & 6 & 9 \\ \hline 13 & 2 & 3 & 16 \\ \hline \end{array} $$

画像の魔方陣では、縦・横・斜めのどの列も合計が34になっていることが分かります。この性質を利用して、段階を踏みながらこのような表を出力してみます。

魔方陣の性質を利用して生成してみる

4次魔方陣を求めるプログラム | 大同大学』にあるアルゴリズムを参考にして、Javaで実装してみます。

MakeMagicSquare44.java
  1import java.util.ArrayList;
  2import java.util.Collections;
  3import java.util.List;
  4
  5public class MakeMagicSquare44 {
  6
  7  /** 1から16までを格納するArrayList */
  8  List<Integer> list = new ArrayList<Integer>();
  9
 10  /** 完成した魔方陣の数表を格納する配列 */
 11  int array[] = new int[16];
 12
 13  public static void main(String[] args) {
 14    MakeMagicSquare44 mMagicSquare = new MakeMagicSquare44();
 15    mMagicSquare.execute();
 16    mMagicSquare.showArray();
 17  }
 18
 19  /** 魔方陣の作成 */
 20  private void execute() {
 21    while (true) {
 22      generateList();
 23      array[0] = list.get(0);
 24      list.remove(0);
 25      array[3] = list.get(0);
 26      list.remove(0);
 27      if (!getTwoCombination(0, 3, 12, 15)) {
 28        continue;
 29      }
 30      if (!getTwoCombination(0, 15, 5, 10)) {
 31        continue;
 32      }
 33      if (!getTwoCombination(0, 3, 1, 2)) {
 34        continue;
 35      }
 36      if (!getTwoCombination(3, 12, 6, 9)) {
 37        continue;
 38      }
 39      if (!getLastOne(1, 5, 9, 13)) {
 40        continue;
 41      }
 42      if (!getLastOne(2, 6, 10, 14)) {
 43        continue;
 44      }
 45      if (!getTwoCombination(5, 6, 4, 7)) {
 46        continue;
 47      }
 48      if (!getLastOne(0, 4, 12, 8)) {
 49        continue;
 50      }
 51      if (!getLastOne(3, 7, 15, 11)) {
 52        continue;
 53      }
 54      break;
 55    }
 56  }
 57
 58  /** listに1~16を格納しシャッフルする */
 59  private void generateList() {
 60    list.clear();
 61    for (int i = 1; i <= 16; i++) {
 62      list.add(i);
 63    }
 64    Collections.shuffle(list);
 65  }
 66
 67  /** 数字が2つ埋まっている列に対して、残りを数字をlistから決定する */
 68  private boolean getTwoCombination(int index1, int index2, int index3, int index4) {
 69    for (int i = 0; i < list.size() - 1; i++) {
 70      for (int j = i + 1; j < list.size(); j++) {
 71        if (array[index1] + array[index2] + list.get(i) + list.get(j) == 34) {
 72          array[index3] = list.get(i);
 73          array[index4] = list.get(j);
 74          list.remove(list.indexOf(array[index3]));
 75          list.remove(list.indexOf(array[index4]));
 76          return true;
 77        }
 78      }
 79    }
 80    return false;
 81  }
 82
 83  /** 数字が3つ埋まっている列に対して、残りを数字をlistから決定する */
 84  private boolean getLastOne(int index1, int index2, int index3, int index4) {
 85    for (int i = 0; i < list.size(); i++) {
 86      if (array[index1] + array[index2] + array[index3] + list.get(i) == 34) {
 87        array[index4] = list.get(i);
 88        list.remove(list.indexOf(list.get(i)));
 89        return true;
 90      }
 91    }
 92    return false;
 93  }
 94
 95  /** 配列を数表形式で出力する */
 96  private void showArray() {
 97    for (int i = 0; i < 16; i++) {
 98      System.out.printf("%3d", array[i]);
 99      if ((i + 1) % 4 == 0) {
100        System.out.println();
101      }
102    }
103  }
104}
出力結果(一例)
1  8 13 11  2
2  5 10 16  3
3 12  7  1 14
4  9  4  6 15

魔方陣の性質を利用して順に数字を求めていくことで、比較的簡単に生成することができました。


今回は、Javaで16マス魔方陣を作成してみました。以上で記事を終わりにします。

関連記事