From 005d84d7807425594337401751728866b46a1d7a Mon Sep 17 00:00:00 2001 From: Graham Cox Date: Fri, 11 Aug 2023 11:57:48 +0100 Subject: [PATCH] BAEL-6813: Creating a Magic Square in Java (#14572) --- core-java-modules/core-java-leetcode/pom.xml | 39 ++++ .../magicsquare/GenerationUnitTest.java | 45 +++++ .../leetcode/magicsquare/MagicSquare.java | 186 ++++++++++++++++++ .../magicsquare/ValidationUnitTest.java | 21 ++ core-java-modules/pom.xml | 1 + 5 files changed, 292 insertions(+) create mode 100644 core-java-modules/core-java-leetcode/pom.xml create mode 100644 core-java-modules/core-java-leetcode/src/test/java/com/baeldung/leetcode/magicsquare/GenerationUnitTest.java create mode 100644 core-java-modules/core-java-leetcode/src/test/java/com/baeldung/leetcode/magicsquare/MagicSquare.java create mode 100644 core-java-modules/core-java-leetcode/src/test/java/com/baeldung/leetcode/magicsquare/ValidationUnitTest.java diff --git a/core-java-modules/core-java-leetcode/pom.xml b/core-java-modules/core-java-leetcode/pom.xml new file mode 100644 index 0000000000..eb91308c64 --- /dev/null +++ b/core-java-modules/core-java-leetcode/pom.xml @@ -0,0 +1,39 @@ + + + 4.0.0 + core-java-leetcode + core-java-leetcode + jar + + + com.baeldung + parent-modules + 1.0.0-SNAPSHOT + ../../pom.xml + + + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + ${maven-compiler-plugin.version} + + ${maven.compiler.source.version} + ${maven.compiler.target.version} + + + + + + + 11 + 11 + + + diff --git a/core-java-modules/core-java-leetcode/src/test/java/com/baeldung/leetcode/magicsquare/GenerationUnitTest.java b/core-java-modules/core-java-leetcode/src/test/java/com/baeldung/leetcode/magicsquare/GenerationUnitTest.java new file mode 100644 index 0000000000..308c655bd1 --- /dev/null +++ b/core-java-modules/core-java-leetcode/src/test/java/com/baeldung/leetcode/magicsquare/GenerationUnitTest.java @@ -0,0 +1,45 @@ +package com.baeldung.leetcode.magicsquare; + +import org.junit.jupiter.api.Test; + +public class GenerationUnitTest { + @Test + public void testGenerate3x3() { + MagicSquare magicSquare = new MagicSquare(3); + System.out.println(magicSquare); + + magicSquare.validate(); + } + + @Test + public void testGenerate9x9() { + MagicSquare magicSquare = new MagicSquare(9); + System.out.println(magicSquare); + + magicSquare.validate(); + } + + @Test + public void testGenerate12x12() { + MagicSquare magicSquare = new MagicSquare(12); + System.out.println(magicSquare); + + magicSquare.validate(); + } + + @Test + public void testGenerate10x10() { + MagicSquare magicSquare = new MagicSquare(10); + System.out.println(magicSquare); + + magicSquare.validate(); + } + + @Test + public void testGenerate18x18() { + MagicSquare magicSquare = new MagicSquare(18); + System.out.println(magicSquare); + + magicSquare.validate(); + } +} diff --git a/core-java-modules/core-java-leetcode/src/test/java/com/baeldung/leetcode/magicsquare/MagicSquare.java b/core-java-modules/core-java-leetcode/src/test/java/com/baeldung/leetcode/magicsquare/MagicSquare.java new file mode 100644 index 0000000000..5e16f2e0db --- /dev/null +++ b/core-java-modules/core-java-leetcode/src/test/java/com/baeldung/leetcode/magicsquare/MagicSquare.java @@ -0,0 +1,186 @@ +package com.baeldung.leetcode.magicsquare; + +import org.junit.platform.commons.util.StringUtils; + +import java.util.stream.IntStream; + +public class MagicSquare { + private int[][] cells; + + public MagicSquare(int n) { + this.cells = new int[n][]; + + for (int i = 0; i < n; ++i) { + this.cells[i] = new int[n]; + } + + if (n % 2 == 1) { + populateOdd(); + } else if (n % 4 == 0) { + populateDoubleEven(); + } else if (n >= 6) { + populateSingleEven(); + } + } + + private void populateOdd() { + int n = getN(); + + populateOddArea(0, 0, n, 0); + } + + private void populateOddArea(int xOffset, int yOffset, int n, int numberOffset) { + int y = 0; + int x = (n - 1) / 2; + setCell(xOffset + x, yOffset + y, numberOffset + 1); + + for (int number = 2; number <= n * n; ++number) { + int nextX = x + 1; + if (nextX == n) { + nextX = 0; + } + + int nextY = y - 1; + if (nextY == -1) { + nextY = n - 1; + } + + if (getCell(xOffset + nextX, yOffset + nextY) != 0) { + nextX = x; + + nextY = y + 1; + if (nextY == n) { + nextY = 0; + } + } + + setCell(xOffset + nextX, yOffset + nextY, numberOffset + number); + + x = nextX; + y = nextY; + } + } + + private void populateDoubleEven() { + int n = getN(); + int number = 1; + + for (int y = 0; y < n; ++y) { + for (int x = 0; x < n; ++x) { + boolean highlighted = false; + + if ((y < n/4 || y >= 3*n/4) && (x >= n/4 && x < 3*n/4)) { + highlighted = true; + } else if ((x < n/4 || x >= 3*n/4) && (y >= n/4 && y < 3*n/4)) { + highlighted = true; + } + + if (highlighted) { + setCell(x, y, (n * n) - number + 1); + } else { + setCell(x, y, number); + } + + number += 1; + } + } + } + + private void populateSingleEven() { + int n = getN(); + int halfN = n/2; + int swapSize = (int) n/4; + + populateOddArea(0, 0, halfN, 0); + populateOddArea(halfN, halfN, halfN, halfN * halfN); + populateOddArea(halfN, 0, halfN, (halfN * halfN) * 2); + populateOddArea(0, halfN, halfN, (halfN * halfN) * 3); + + for (int x = 0; x < swapSize; ++x) { + swapCells(x, 0, x, halfN); + swapCells(x, halfN - 1, x, n - 1); + + for (int y = 1; y < halfN - 1; ++y) { + swapCells(x + 1, y, x + 1, y + halfN); + } + } + + for (int x = 0; x < swapSize - 1; ++x) { + for (int y = 0; y < halfN; ++y) { + swapCells(n - x - 1, y, n - x - 1, y + halfN); + } + } + + } + + private void swapCells(int x1, int y1, int x2, int y2) { + int cell1 = getCell(x1, y1); + int cell2 = getCell(x2, y2); + + setCell(x1, y1, cell2); + setCell(x2, y2, cell1); + } + + public int getN() { + return cells.length; + } + + public int getCell(int x, int y) { + return cells[x][y]; + } + + public void setCell(int x, int y, int value) { + cells[x][y] = value; + } + + public void validate() { + int n = getN(); + int expectedValue = ((n * n * n) + n) / 2; + + // Diagonals + if (IntStream.range(0, n).map(i -> getCell(i, i)).sum() != expectedValue) { + throw new IllegalStateException("Leading diagonal is not the expected value"); + } + if (IntStream.range(0, n).map(i -> getCell(i, n - i - 1)).sum() != expectedValue) { + throw new IllegalStateException("Trailing diagonal is not the expected value"); + } + + // Rows + IntStream.range(0, n).forEach(y -> { + if (IntStream.range(0, n).map(x -> getCell(x, y)).sum() != expectedValue) { + throw new IllegalStateException("Row is not the expected value"); + } + }); + + // Cols + IntStream.range(0, n).forEach(x -> { + if (IntStream.range(0, n).map(y -> getCell(x, y)).sum() != expectedValue) { + throw new IllegalStateException("Column is not the expected value"); + } + }); + } + + public String toString() { + int n = getN(); + int largestNumberLength = Integer.toString(n * n).length(); + String formatString = " %0" + largestNumberLength + "d "; + + StringBuilder sb = new StringBuilder(); + + for (int y = 0; y < n; ++y) { + for (int x = 0; x < n; ++x) { + int value = getCell(x, y); + if (value == 0) { + sb.append(" "); + sb.append(".".repeat(largestNumberLength)); + sb.append(" "); + } else { + sb.append(String.format(formatString, value)); + } + } + sb.append("\n"); + } + + return sb.toString(); + } +} diff --git a/core-java-modules/core-java-leetcode/src/test/java/com/baeldung/leetcode/magicsquare/ValidationUnitTest.java b/core-java-modules/core-java-leetcode/src/test/java/com/baeldung/leetcode/magicsquare/ValidationUnitTest.java new file mode 100644 index 0000000000..93f36931e6 --- /dev/null +++ b/core-java-modules/core-java-leetcode/src/test/java/com/baeldung/leetcode/magicsquare/ValidationUnitTest.java @@ -0,0 +1,21 @@ +package com.baeldung.leetcode.magicsquare; + +import org.junit.jupiter.api.Test; + +public class ValidationUnitTest { + @Test + public void testValidate3x3() { + MagicSquare magicSquare = new MagicSquare(3); + magicSquare.setCell(0, 0, 8); + magicSquare.setCell(1, 0, 1); + magicSquare.setCell(2, 0, 6); + magicSquare.setCell(0, 1, 3); + magicSquare.setCell(1, 1, 5); + magicSquare.setCell(2, 1, 7); + magicSquare.setCell(0, 2, 4); + magicSquare.setCell(1, 2, 9); + magicSquare.setCell(2, 2, 2); + + magicSquare.validate(); + } +} diff --git a/core-java-modules/pom.xml b/core-java-modules/pom.xml index e9bb86e500..a6f0382186 100644 --- a/core-java-modules/pom.xml +++ b/core-java-modules/pom.xml @@ -108,6 +108,7 @@ core-java-lang-operators-2 core-java-lang-syntax core-java-lang-syntax-2 + core-java-leetcode core-java-locale core-java-networking core-java-networking-2