# ==============================================================================
"""LATIN : generate a random latin square"""
# ==============================================================================
__author__  = "Christophe Schlick modified by Philippe Blasi"
__version__ = "1.0" # draft implementation without command line options
__date__    = "2022-11-12"
__usage__   = """
Input : n = size of grid"""
# ==============================================================================
from random import randrange
# ------------------------------------------------------------------------------
def latin(n:int) -> list:
  """generate a matrix containing a random n by n latin square"""
  mat = [[1+(p+q)%n for q in range(n)] for p in range(n)] # initial matrix
  for loop in range(999*n): # loop 999*n times to get pretty good shuffling
    p, q = randrange(n), randrange(n)
    for r in range(n): # exchange row p with row q
      mat[p][r], mat[q][r] = mat[q][r], mat[p][r]
    p, q = randrange(n), randrange(n)
    for r in range(n): # exchange col p with col q
      mat[r][p], mat[r][q] = mat[r][q], mat[r][p]
  return mat
# ------------------------------------------------------------------------------
def grid(mat:list) -> str:
  """return a string containing a graphical grid generated from matrix 'mat'"""
  # find the maximum number of digits required for the matrix elements
  digits = len(str(max(val for row in mat for val in row)))
  # create row and col separators, accounting for the maximum number of digits
  col_sep, row_sep = '|', f"\n{(('+' + '-'*digits) * len(mat))}+\n"
  # convert each matrix element to a string with a fixed length
  mat = [[f"{val:{digits}}" for val in row] for row in mat]
  # finally join everything together as a multi-line string
  rows = [f"{col_sep}{col_sep.join(cols)}{col_sep}" for cols in mat]
  return f"{row_sep}{row_sep.join(rows)}{row_sep}"
# ------------------------------------------------------------------------------
def main():
  """main program of the "latin" module"""
  print(f"{'-'*80}\n{__doc__}{__usage__}\n{'-'*80}") # show info (doc and usage)
  while True:
    line = input("<> Enter value of 'n' : ")
    if line == '': break
    try:
      print(grid(latin(int(line))))
    except ValueError:
      print("Error : invalid input value")
# ------------------------------------------------------------------------------
if __name__ == '__main__':
  main()
# ==============================================================================
