mirror of https://github.com/tLDP/LDP
113 lines
3.2 KiB
Bash
113 lines
3.2 KiB
Bash
#!/bin/bash
|
|
# msquare.sh
|
|
# Magic Square generator (odd-order squares only!)
|
|
|
|
# Author: mendel cooper
|
|
# reldate: 19 Jan. 2009
|
|
# License: Public Domain
|
|
# A C-program by the very talented Kwon Young Shin inspired this script.
|
|
# http://user.chollian.net/~brainstm/MagicSquare.htm
|
|
|
|
# Definition: A "magic square" is a two-dimensional array
|
|
# of integers in which all the rows, columns,
|
|
# and *long* diagonals add up to the same number.
|
|
# Being "square," the array has the same number
|
|
# of rows and columns. That number is the "order."
|
|
# An example of a magic square of order 3 is:
|
|
# 8 1 6
|
|
# 3 5 7
|
|
# 4 9 2
|
|
# All the rows, columns, and the two long diagonals add up to 15.
|
|
|
|
|
|
# Globals
|
|
EVEN=2
|
|
MAXSIZE=31 # 31 rows x 31 cols.
|
|
E_usage=90 # Invocation error.
|
|
dimension=
|
|
declare -i square
|
|
|
|
usage_message ()
|
|
{
|
|
echo "Usage: $0 order"
|
|
echo " ... where \"order\" (square size) is an ODD integer"
|
|
echo " in the range 3 - 31."
|
|
# Actually works for squares up to order 159,
|
|
#+ but large squares will not display pretty-printed in a term window.
|
|
# Try increasing MAXSIZE, above.
|
|
exit $E_usage
|
|
}
|
|
|
|
|
|
calculate () # Here's where the actual work gets done.
|
|
{
|
|
local row col index dimadj j k cell_val=1
|
|
dimension=$1
|
|
|
|
let "dimadj = $dimension * 3"; let "dimadj /= 2" # x 1.5, then truncate.
|
|
|
|
for ((j=0; j < dimension; j++))
|
|
do
|
|
for ((k=0; k < dimension; k++))
|
|
do # Calculate indices, then convert to 1-dim. array index.
|
|
# Bash doesn't support multidimensional arrays. Pity.
|
|
let "col = $k - $j + $dimadj"; let "col %= $dimension"
|
|
let "row = $j * 2 - $k + $dimension"; let "row %= $dimension"
|
|
let "index = $row*($dimension) + $col"
|
|
square[$index]=cell_val; ((cell_val++))
|
|
done
|
|
done
|
|
} # Plain math, visualization not required.
|
|
|
|
|
|
print_square () # Output square, one row at a time.
|
|
{
|
|
local row col idx d1
|
|
let "d1 = $dimension - 1" # Adjust for zero-indexed array.
|
|
|
|
for row in $(seq 0 $d1)
|
|
do
|
|
|
|
for col in $(seq 0 $d1)
|
|
do
|
|
let "idx = $row * $dimension + $col"
|
|
printf "%3d " "${square[idx]}"; echo -n " "
|
|
done # Displays up to 13th order neatly in 80-column term window.
|
|
|
|
echo # Newline after each row.
|
|
done
|
|
}
|
|
|
|
|
|
#################################################
|
|
if [[ -z "$1" ]] || [[ "$1" -gt $MAXSIZE ]]
|
|
then
|
|
usage_message
|
|
fi
|
|
|
|
let "test_even = $1 % $EVEN"
|
|
if [ $test_even -eq 0 ]
|
|
then # Can't handle even-order squares.
|
|
usage_message
|
|
fi
|
|
|
|
calculate $1
|
|
print_square # echo "${square[@]}" # DEBUG
|
|
|
|
exit $?
|
|
#################################################
|
|
|
|
|
|
# Exercises:
|
|
# ---------
|
|
# 1) Add a function to calculate the sum of each row, column,
|
|
# and *long* diagonal. The sums must match.
|
|
# This is the "magic constant" of that particular order square.
|
|
# 2) Have the print_square function auto-calculate how much space
|
|
# to allot between square elements for optimized display.
|
|
# This might require parameterizing the "printf" line.
|
|
# 3) Add appropriate functions for generating magic squares
|
|
# with an *even* number of rows/columns.
|
|
# This is non-trivial(!).
|
|
# See the URL for Kwon Young Shin, above, for help.
|