Sunday, December 30, 2018

Magic squares generator in C

2021-11-10: NOTE: I rewrote the program to make it faster in magic-square.

A magic square is a table with equal number of rows and columns that is filled with all the numbers from 1 to NxN (being N the number of rows) in a way that verifies that the sum of the numbers in any row, in any column and in any of the two diagonals gives the same result in all cases, which is called the magic constant. If you choose a different initial number than 1 for filling the square (even zero or negative) and a different increment than 1 to get the following numbers, you will also get the same number of magic squares although the magic constant will change.

Because by rotation or reflection of a magic square you can get other 8 magic squares, only one of those variations (or trivial solutions) is counted. One magic square of size 1x1 exists, zero magic squares of size 2x2 exist and one magic square of size 3x3 exist (with 8 rotations and/or reflections) whose lines sum 15. If you choose the magic square of size 3x3 with the minimum corners, you get this one (printed by my magic square generator):

 2 | 9 | 4 
---+---+---
 7 | 5 | 3 
---+---+---
 6 | 1 | 8 

Exist 880 magic squares of size 4x4 (7040 if you count the trivial solutions) with sum 34, and the magic squares of size 5x5 with sum 65 are many many more, so I created this magic square generator to count them and verify the number of magic squares that others found. Because that number is so big and the program cannot generate all magic squares in a short time, you can can restart the counting from any point by choosing the numbers of the corners with the -c option, although it only accepts ordered numbers for the initial corners. The minimum corners that I have found that generate solutions is this:

$ ./magic-square -c1,2,5,22 5
  1 | 18 | 20 | 24 |  2 
----+----+----+----+----
 23 |  8 |  6 | 12 | 16 
----+----+----+----+----
 19 |  3 | 25 |  7 | 11 
----+----+----+----+----
 17 | 21 |  4 |  9 | 14 
----+----+----+----+----
  5 | 15 | 10 | 13 | 22 
...

To stop the program you can hit Control+C or wait until it reaches the last corners 22,23,24,25. The available options are shown by executing the program without arguments. The -q option counts the solutions without printing them. Happy searching!

Thursday, September 13, 2018

Repeating strings with a separator in Java

The problem of joining strings with a separator is a very common one in programming, but is surprising the number of solutions that different programmers find to that simple task.
Recently I had to repeat a given string ("?" for example) a given number of times but adding a separator between each string ("," for example). I searched for that code in other places of the project and I found many ways, including these:
if (n > 0) {
 for (int i = 1; i < n; i++) {
  buf.append("?,");
 }
 buf.append("?");
}

if (n > 0) {
 for (int i = 0; i < n; i++) {
  buf.append("?,");
 }
 buf.setLength(buf.length() - 1);
}

for (int i = 0; i < n; i++) {
 buf.append("?");
 if (i < n - 1) {
  buf.append(",");
 }
}

boolean first = true;
for (int i = 0; i < n; i++) {
 if (first) {
  first = false;
 } else {
  buf.append(",");
 }
 buf.append("?");
}
To stop this madness, I decided to create a method for reducing all those variations to simpler and less error-prone calls:
/**
 * Appends a string to a buffer a specified number of times,
 * optionally inserting another string as a separator.
 *
 * @param sb The buffer that will have the string appended, if null a new one is created.
 * @param str The string to append.
 * @param n The number of times that the string will be appended.
 * @param sep An optional separator appended between two strings.
 *
 * @return The specified buffer with the string appended or a new one if it was null.
 */
public static StringBuilder repeatAppend(StringBuilder sb, String str, int n, String sep) {
  if (sb == null) {
    sb = new StringBuilder();
  }
  if (n > 0) {
    sb.append(str);
    if (sep != null) {
      for (int i = 1; i < n; i++) {
        sb.append(sep).append(str);
      }
    } else {
      for (int i = 1; i < n; i++) {
        sb.append(str);
      }
    }
  }
  return sb;
}

Be free to use it in your project and happy coding!

Update: Apache Commons StringUtils.repeat(str, sep, n) and Java Collections.nCopies(n, str) with String.join(sep, collection) are alternatives to this method, but our method allows adding to an existing StringBuilder and the others need to create it and destroy it for that. Added return sb; to allow an inline use.