# syntax: GAWK -f MAGNANIMOUS_NUMBERS.AWK
# converted from C
BEGIN {
    magnanimous(1,45)
    magnanimous(241,250)
    magnanimous(391,400)
    exit(0)
}
function is_magnanimous(n,  p,q,r) {
    if (n < 10) { return(1) }
    for (p=10; ; p*=10) {
      q = int(n/p)
      r = n % p
      if (!is_prime(q+r)) { return(0) }
      if (q < 10) { break }
    }
    return(1)
}
function is_prime(n,  d) {
    d = 5
    if (n < 2) { return(0) }
    if (!(n % 2)) { return(n == 2) }
    if (!(n % 3)) { return(n == 3) }
    while (d*d <= n) {
      if (!(n % d)) { return(0) }
      d += 2
      if (!(n % d)) { return(0) }
      d += 4
    }
    return(1)
}
function magnanimous(start,stop,  count,i) {
    printf("%d-%d:",start,stop)
    for (i=0; count<stop; ++i) {
      if (is_magnanimous(i)) {
        if (++count >= start) {
          printf(" %d",i)
        }
      }
    }
    printf("\n")
}


#include <stdio.h>
#include <string.h>

typedef int bool;
typedef unsigned long long ull;

#define TRUE 1
#define FALSE 0

/* OK for 'small' numbers. */
bool is_prime(ull n) {
    ull d;
    if (n < 2) return FALSE;
    if (!(n % 2)) return n == 2;
    if (!(n % 3)) return n == 3;
    d = 5;
    while (d * d <= n) {
        if (!(n % d)) return FALSE;
        d += 2;
        if (!(n % d)) return FALSE;
        d += 4;
    }
    return TRUE;
}

void ord(char *res, int n) {
    char suffix[3];
    int m = n % 100;
    if (m >= 4 && m <= 20) {
        sprintf(res,"%dth", n);
        return;
    }
    switch(m % 10) {
        case 1:
            strcpy(suffix, "st");
            break;
        case 2:
            strcpy(suffix, "nd");
            break;
        case 3:
            strcpy(suffix, "rd");
            break;
        default:
            strcpy(suffix, "th");
            break;
    }
    sprintf(res, "%d%s", n, suffix);
}

bool is_magnanimous(ull n) {
    ull p, q, r;
    if (n < 10) return TRUE;
    for (p = 10; ; p *= 10) {
        q = n / p;
        r = n % p;
        if (!is_prime(q + r)) return FALSE;
        if (q < 10) break;
    }
    return TRUE;
}

void list_mags(int from, int thru, int digs, int per_line) {
    ull i = 0;
    int c = 0;
    char res1[13], res2[13];
    if (from < 2) {
        printf("\nFirst %d magnanimous numbers:\n", thru);
    } else {
        ord(res1, from);
        ord(res2, thru);
        printf("\n%s through %s magnanimous numbers:\n", res1, res2);
    }
    for ( ; c < thru; ++i) {
        if (is_magnanimous(i)) {
            if (++c >= from) {
                printf("%*llu ", digs, i);
                if (!(c % per_line)) printf("\n");
            }
        }
    }
}

int main() {
    list_mags(1, 45, 3, 15);
    list_mags(241, 250, 1, 10);
    list_mags(391, 400, 1, 10);
    return 0;
}


using System; using static System.Console;

class Program {

  static bool[] np; // not-prime array

  static void ms(long lmt) { // populates array, a not-prime is true
    np = new bool[lmt]; np[0] = np[1] = true;
    for (long n = 2, j = 1; n < lmt; n += j, j = 2) if (!np[n])
        for (long k = n * n; k < lmt; k += n) np[k] = true; }

  static bool is_Mag(long n) { long res, rem;
    for (long p = 10; n >= p; p *= 10) {
      res = Math.DivRem (n, p, out rem);
      if (np[res + rem]) return false; } return true; }

  static void Main(string[] args) { ms(100_009); string mn;
    WriteLine("First 45{0}", mn = " magnanimous numbers:");
    for (long l = 0, c = 0; c < 400; l++) if (is_Mag(l)) {
      if (c++ < 45 || (c > 240 && c <= 250) || c > 390)
        Write(c <= 45 ? "{0,4} " : "{0,8:n0} ", l);
      if (c < 45 && c % 15 == 0) WriteLine();
      if (c == 240) WriteLine ("\n\n241st through 250th{0}", mn);
      if (c == 390) WriteLine ("\n\n391st through 400th{0}", mn); } }
}


#include <iomanip>
#include <iostream>

bool is_prime(unsigned int n) {
    if (n < 2)
        return false;
    if (n % 2 == 0)
        return n == 2;
    if (n % 3 == 0)
        return n == 3;
    for (unsigned int p = 5; p * p <= n; p += 4) {
        if (n % p == 0)
            return false;
        p += 2;
        if (n % p == 0)
            return false;
    }
    return true;
}

bool is_magnanimous(unsigned int n) {
    for (unsigned int p = 10; n >= p; p *= 10) {
        if (!is_prime(n % p + n / p))
            return false;
    }
    return true;
}

int main() {
    unsigned int count = 0, n = 0;
    std::cout << "First 45 magnanimous numbers:\n";
    for (; count < 45; ++n) {
        if (is_magnanimous(n)) {
            if (count > 0)
                std::cout << (count % 15 == 0 ? "\n" : ", ");
            std::cout << std::setw(3) << n;
            ++count;
        }
    }
    std::cout << "\n\n241st through 250th magnanimous numbers:\n";
    for (unsigned int i = 0; count < 250; ++n) {
        if (is_magnanimous(n)) {
            if (count++ >= 240) {
                if (i++ > 0)
                    std::cout << ", ";
                std::cout << n;
            }
        }
    }
    std::cout << "\n\n391st through 400th magnanimous numbers:\n";
    for (unsigned int i = 0; count < 400; ++n) {
        if (is_magnanimous(n)) {
            if (count++ >= 390) {
                if (i++ > 0)
                    std::cout << ", ";
                std::cout << n;
            }
        }
    }
    std::cout << '\n';
    return 0;
}


// Generate Magnanimous numbers. Nigel Galloway: March 20th., 2020
let rec fN n g = match (g/n,g%n) with
                  (0,_)                    -> true
                 |(α,β) when isPrime (α+β) -> fN (n*10) g
                 |_                        -> false
let Magnanimous = let Magnanimous = fN 10 in seq{yield! {0..9}; yield! Seq.initInfinite id |> Seq.skip 10 |> Seq.filter Magnanimous}


USING: grouping io kernel lists lists.lazy math math.functions
math.primes math.ranges prettyprint sequences ;

: magnanimous? ( n -- ? )
    dup 10 < [ drop t ] [
        dup log10 >integer [1,b] [ 10^ /mod + prime? not ] with
        find nip >boolean not
    ] if ;

: magnanimous ( n -- seq )
    0 lfrom [ magnanimous? ] lfilter ltake list>array ;

: show ( seq from to -- ) rot subseq 15 group simple-table. nl ;

400 magnanimous
[ "First 45 magnanimous numbers" print 0 45 show ]
[ "241st through 250th magnanimous numbers" print 240 250 show ]
[ "391st through 400th magnanimous numbers" print 390 400 show ]
tri


#include "isprime.bas"

dim as uinteger magn(0 to 399), i, n=10, j
dim as string ns, lefty, righty
for i = 0 to 9
    magn(i) = i    'all single digit ints are magnanimous by definition
next i

while i<400
    n += 1
    ns = str(n)
    for j = 1 to len(ns)-1
        lefty = left(ns, j)
        righty = right(ns, len(ns)-j)
        if not isprime( val(lefty) + val(righty) ) then continue while
    next j
    magn(i) = n
    i+=1
wend

for i=0 to 44
    print i+1,magn(i)
next i

for i=240 to 249
    print i+1,magn(i)
next i

for i=390 to 399
    print i+1,magn(i)
next i


package main

import "fmt"

// OK for 'small' numbers.
func isPrime(n uint64) bool {
    switch {
    case n < 2:
        return false
    case n%2 == 0:
        return n == 2
    case n%3 == 0:
        return n == 3
    default:
        d := uint64(5)
        for d*d <= n {
            if n%d == 0 {
                return false
            }
            d += 2
            if n%d == 0 {
                return false
            }
            d += 4
        }
        return true
    }
}

func ord(n int) string {
    m := n % 100
    if m >= 4 && m <= 20 {
        return fmt.Sprintf("%dth", n)
    }
    m %= 10
    suffix := "th"
    if m < 4 {
        switch m {
        case 1:
            suffix = "st"
        case 2:
            suffix = "nd"
        case 3:
            suffix = "rd"
        }
    }
    return fmt.Sprintf("%d%s", n, suffix)
}

func isMagnanimous(n uint64) bool {
    if n < 10 {
        return true
    }
    for p := uint64(10); ; p *= 10 {
        q := n / p
        r := n % p
        if !isPrime(q + r) {
            return false
        }
        if q < 10 {
            break
        }
    }
    return true
}

func listMags(from, thru, digs, perLine int) {
    if from < 2 {
        fmt.Println("\nFirst", thru, "magnanimous numbers:")
    } else {
        fmt.Printf("\n%s through %s magnanimous numbers:\n", ord(from), ord(thru))
    }
    for i, c := uint64(0), 0; c < thru; i++ {
        if isMagnanimous(i) {
            c++
            if c >= from {
                fmt.Printf("%*d ", digs, i)
                if c%perLine == 0 {
                    fmt.Println()
                }
            }
        }
    }
}

func main() {
    listMags(1, 45, 3, 15)
    listMags(241, 250, 1, 10)
    listMags(391, 400, 1, 10)
}


import Data.List.Split ( chunksOf )
import Data.List ( (!!) )

isPrime :: Int -> Bool
isPrime n
   |n == 2 = True
   |n == 1 = False
   |otherwise = null $ filter (\i -> mod n i == 0 ) [2 .. root]
   where
      root :: Int
      root = floor $ sqrt $ fromIntegral n

isMagnanimous :: Int -> Bool
isMagnanimous n = all isPrime $ map (\p -> fst p + snd p ) numberPairs
 where
  str:: String
  str = show n
  splitStrings :: [(String , String)]
  splitStrings = map (\i -> splitAt i str) [1 .. length str - 1]
  numberPairs :: [(Int , Int)]
  numberPairs = map (\p -> ( read $ fst p , read $ snd p )) splitStrings

printInWidth :: Int -> Int -> String
printInWidth number width = replicate ( width - l ) ' ' ++ str
 where
  str :: String
  str = show number
  l :: Int
  l = length str

solution :: [Int]
solution = take 400 $ filter isMagnanimous [0 , 1 ..]

main :: IO ( )
main = do
   let numbers = solution
       numberlines = chunksOf 10 $ take 45 numbers
   putStrLn "First 45 magnanimous numbers:"
   mapM_ (\li -> putStrLn (foldl1 ( ++ ) $ map (\n -> printInWidth n 6 )
    li )) numberlines
   putStrLn "241'st to 250th magnanimous numbers:"
   putStr $ show ( numbers !! 240 )
   putStrLn ( foldl1 ( ++ ) $ map(\n -> printInWidth n 8 ) $ take 9 $
    drop 241 numbers )
   putStrLn "391'st to 400th magnanimous numbers:"
   putStr $ show ( numbers !! 390 )
   putStrLn ( foldl1 ( ++ ) $ map(\n -> printInWidth n 8 ) $ drop 391 numbers)


import java.util.ArrayList;
import java.util.List;

public class MagnanimousNumbers {

    public static void main(String[] args) {
        runTask("Find and display the first 45 magnanimous numbers.", 1, 45);
        runTask("241st through 250th magnanimous numbers.", 241, 250);
        runTask("391st through 400th magnanimous numbers.", 391, 400);
    }

    private static void runTask(String message, int startN, int endN) {
        int count = 0;
        List<Integer> nums = new ArrayList<>();
        for ( int n = 0 ; count < endN ; n++ ) {
            if ( isMagnanimous(n) ) {
                nums.add(n);
                count++;
            }
        }
        System.out.printf("%s%n", message);
        System.out.printf("%s%n%n", nums.subList(startN-1, endN));
    }

    private static boolean isMagnanimous(long n) {
        if ( n >= 0 && n <= 9 ) {
            return true;
        }
        long q = 11;
        for ( long div = 10 ; q >= 10 ; div *= 10 ) {
            q = n / div;
            long r = n % div;
            if ( ! isPrime(q+r) ) {
                return false;
            }
        }
        return true;
    }

    private static final int MAX = 100_000;
    private static final boolean[] primes = new boolean[MAX];
    private static boolean SIEVE_COMPLETE = false;

    private static final boolean isPrimeTrivial(long test) {
        if ( ! SIEVE_COMPLETE ) {
            sieve();
            SIEVE_COMPLETE = true;
        }
        return primes[(int) test];
    }

    private static final void sieve() {
        //  primes
        for ( int i = 2 ; i < MAX ; i++ ) {
            primes[i] = true;
        }
        for ( int i = 2 ; i < MAX ; i++ ) {
            if ( primes[i] ) {
                for ( int j = 2*i ; j < MAX ; j += i ) {
                    primes[j] = false;
                }
            }
        }
    }

    //  See http://primes.utm.edu/glossary/page.php?sort=StrongPRP
    public static final boolean isPrime(long testValue) {
        if ( testValue == 2 ) return true;
        if ( testValue % 2 == 0 ) return false;
        if ( testValue <= MAX ) return isPrimeTrivial(testValue);
        long d = testValue-1;
        int s = 0;
        while ( d % 2 == 0 ) {
            s += 1;
            d /= 2;
        }
        if ( testValue < 1373565L ) {
            if ( ! aSrp(2, s, d, testValue) ) {
                return false;
            }
            if ( ! aSrp(3, s, d, testValue) ) {
                return false;
            }
            return true;
        }
        if ( testValue < 4759123141L ) {
            if ( ! aSrp(2, s, d, testValue) ) {
                return false;
            }
            if ( ! aSrp(7, s, d, testValue) ) {
                return false;
            }
            if ( ! aSrp(61, s, d, testValue) ) {
                return false;
            }
            return true;
        }
        if ( testValue < 10000000000000000L ) {
            if ( ! aSrp(3, s, d, testValue) ) {
                return false;
            }
            if ( ! aSrp(24251, s, d, testValue) ) {
                return false;
            }
            return true;
        }
        //  Try 5 "random" primes
        if ( ! aSrp(37, s, d, testValue) ) {
            return false;
        }
        if ( ! aSrp(47, s, d, testValue) ) {
            return false;
        }
        if ( ! aSrp(61, s, d, testValue) ) {
            return false;
        }
        if ( ! aSrp(73, s, d, testValue) ) {
            return false;
        }
        if ( ! aSrp(83, s, d, testValue) ) {
            return false;
        }
        //throw new RuntimeException("ERROR isPrime:  Value too large = "+testValue);
        return true;
    }

    private static final boolean aSrp(int a, int s, long d, long n) {
        long modPow = modPow(a, d, n);
        //System.out.println("a = "+a+", s = "+s+", d = "+d+", n = "+n+", modpow = "+modPow);
        if ( modPow == 1 ) {
            return true;
        }
        int twoExpR = 1;
        for ( int r = 0 ; r < s ; r++ ) {
            if ( modPow(modPow, twoExpR, n) == n-1 ) {
                return true;
            }
            twoExpR *= 2;
        }
        return false;
    }

    private static final long SQRT = (long) Math.sqrt(Long.MAX_VALUE);

    public static final long modPow(long base, long exponent, long modulus) {
        long result = 1;
        while ( exponent > 0 ) {
            if ( exponent % 2 == 1 ) {
                if ( result > SQRT || base > SQRT ) {
                    result = multiply(result, base, modulus);
                }
                else {
                    result = (result * base) % modulus;
                }
            }
            exponent >>= 1;
            if ( base > SQRT ) {
                base = multiply(base, base, modulus);
            }
            else {
                base = (base * base) % modulus;
            }
        }
        return result;
    }

    //  Result is a*b % mod, without overflow.
    public static final long multiply(long a, long b, long modulus) {
        long x = 0;
        long y = a % modulus;
        long t;
        while ( b > 0 ) {
            if ( b % 2 == 1 ) {
                t = x + y;
                x = (t > modulus ? t-modulus : t);
            }
            t = y << 1;
            y = (t > modulus ? t-modulus : t);
            b >>= 1;
        }
        return x % modulus;
    }

}


# To take advantage of gojq's arbitrary-precision integer arithmetic:
def power($b): . as $in | reduce range(0;$b) as $i (1; . * $in);

def divrem($x; $y):
  [$x/$y|floor, $x % $y];


using Primes

function ismagnanimous(n)
    n < 10 && return true
    for i in 1:ndigits(n)-1
        q, r = divrem(n, 10^i)
        !isprime(q + r) && return false
    end
    return true
end

function magnanimous(N)
    mvec, i = Int[], 0
    while length(mvec) < N
        if ismagnanimous(i)
            push!(mvec, i)
        end
        i += 1
    end
    return mvec
end

const mag400 = magnanimous(400)
println("First 45 magnanimous numbers:\n", mag400[1:24], "\n", mag400[25:45])
println("\n241st through 250th magnanimous numbers:\n", mag400[241:250])
println("\n391st through 400th magnanimous numbers:\n", mag400[391:400])


Clear[MagnanimousNumberQ]
MagnanimousNumberQ[Alternatives @@ Range[0, 9]] = True;
MagnanimousNumberQ[n_Integer] := AllTrue[Range[IntegerLength[n] - 1], PrimeQ[Total[FromDigits /@ TakeDrop[IntegerDigits[n], #]]] &]
sel = Select[Range[0, 1000000], MagnanimousNumberQ];
sel[[;; 45]]
sel[[241 ;; 250]]
sel[[391 ;; 400]]


func isPrime(n: Natural): bool =
  if n < 2: return
  if n mod 2 == 0: return n == 2
  if n mod 3 == 0: return n == 3
  var d = 5
  while d * d <= n:
    if n mod d == 0: return false
    inc d, 2
    if n mod d == 0: return false
    inc d, 4
  return true

func isMagnanimous(n: Natural): bool =
  var p = 10
  while true:
    let a = n div p
    let b = n mod p
    if a == 0: break
    if not isPrime(a + b): return false
    p *= 10
  return true

iterator magnanimous(): (int, int) =
  var n, count = 0
  while true:
    if n.isMagnanimous:
      inc count
      yield (count, n)
    inc n

for (i, n) in magnanimous():
  if i in 1..45:
    if i == 1: stdout.write "First 45 magnanimous numbers:\n  "
    stdout.write n, if i == 45: '\n' else: ' '

  elif i in 241..250:
    if i == 241: stdout.write "\n241st through 250th magnanimous numbers:\n  "
    stdout.write n, if i == 250: "\n" else: "  "

  elif i in 391..400:
    if i == 391: stdout.write "\n391st through 400th magnanimous numbers:\n  "
    stdout.write n, if i == 400: "\n" else: "  "

  elif i > 400:
    break


program Magnanimous;
//Magnanimous Numbers
//algorithm find only numbers where all digits are even except the last
//or where all digits are odd except the last
//so 1,11,20,101,1001 will not be found
//starting at 100001  "1>"+x"0"+"1" is not prime because of 1001 not prime
{$IFDEF FPC}
  {$MODE DELPHI}
  {$Optimization ON}
  {$CODEALIGN proc=16}
{$ELSE}
  {$APPTYPE CONSOLE}
{$ENDIF}
{$DEFINE USE_GMP}
uses
  //strUtils, // commatize Numb2USA
  {$IFDEF USE_GMP}gmp,{$ENDIF}
  SysUtils;
const
  MaxLimit = 10*1000*1000 +10;
  MAXHIGHIDX = 10;
type
   tprimes = array of byte;
   tBaseType = Byte;
   tpBaseType = pByte;
   tBase =array[0..15] of tBaseType;
   tNumType = NativeUint;
   tSplitNum = array[0..15] of tNumType;
   tMagList  = array[0..1023] of Uint64;
var
  {$ALIGN 32}
  MagList : tMagList;

  dgtBase5,  // count in Base 5
  dgtORMask, //Mark of used digit (or (1 shl Digit ))
  dgtEvenBase10,
  dgtOddBase10: tbase;

  primes : tprimes;
  {$IFDEF USE_GMP} z : mpz_t;gmp_count :NativeUint;{$ENDIF}
  pPrimes0 : pByte;
  T0: int64;
  HighIdx,num,MagIdx,count,cnt: NativeUint;

  procedure InitPrimes;
  const
    smallprimes :array[0..5] of byte = (2,3,5,7,11,13);
  var
    pPrimes : pByte;
    p,i,j,l : NativeUint;
  begin
    l := 1;
    for j := 0 to High(smallprimes) do
      l*= smallprimes[j];
    //scale primelimit to be multiple of l
    i :=((MaxLimit-1) DIV l+1)*l+1;//+1 should suffice
    setlength(primes,i);
    pPrimes := @primes[0];

    for j := 0 to High(smallprimes) do
    begin
      p := smallprimes[j];
      i := p;
      if j <> 0 then
        p +=p;
      while i <= l do
      begin
        pPrimes[i] := 1;
        inc(i,p)
      end;
    end;
    //turn the prime wheel
    for p := length(primes) div l -1 downto 1 do
      move(pPrimes[1],pPrimes[p*l+1],l);

    l := High(primes);
    //reinsert smallprimes
    for j := 0 to High(smallprimes) do
      pPrimes[smallprimes[j]] := 0;
    pPrimes[1]:=1;
    pPrimes[0]:=1;

    p := smallprimes[High(smallprimes)];
    repeat
      repeat
        inc(p)
      until pPrimes[p] = 0;
      j :=  l div p;
      while (pPrimes[j]<> 0) AND (j>=p) do
        dec(j);
      if j<p then
        BREAK;
      //delta  going downwards no factor 2,3 :-2 -4 -2 -4
      i := (j+1) mod 6;
      if i = 0 then
        i :=4;
      repeat
        while (pPrimes[j]<> 0) AND (j>=p) do
        begin
          dec(j,i);
          i := 6-i;
        end;
        if j<p then
          BREAK;
        pPrimes[j*p] := 1;
        dec(j,i);
        i := 6-i;
      until j<p;
    until false;

    pPrimes0 := pPrimes;
  end;

  procedure InsertSort(pMag:pUint64; Left, Right : NativeInt );
  var
    I, J: NativeInt;
    Pivot : Uint64;
  begin
    for i:= 1 + Left to Right do
    begin
      Pivot:= pMag[i];
      j:= i - 1;
      while (j >= Left) and (pMag[j] > Pivot) do
      begin
        pMag[j+1]:=pMag[j];
        Dec(j);
      end;
      pMag[j+1]:= pivot;
    end;
  end;

  procedure OutBase5;
  var
    pb: tpBaseType;
    i : NativeUint;
  begin
    write(count :10);
    pb:= @dgtBase5[0];
    for i := HighIdx downto 0 do
      write(pb[i]:3);
    write(' : ' );
    pb:= @dgtORMask[0];
    for i := HighIdx downto 0 do
      write(pb[i]:3);
  end;

  function Base10toNum(var dgtBase10: tBase):NativeUint;
  var
    i : NativeInt;
  begin
    Result := 0;
    for i := HighIdx downto 0 do
      Result := Result * 10 + dgtBase10[i];
  end;

  procedure OutSol(cnt:Uint64);
  begin
    writeln(MagIdx:4,cnt:13,Base10toNum(dgtOddBase10):20,
           (Gettickcount64-T0) / 1000: 10: 3, ' s');
  end;

  procedure CnvEvenBase10(lastIdx:NativeInt);
  var
    pdgt : tpBaseType;
    idx: nativeint;
  begin
    pDgt := @dgtEvenBase10[0];
    for idx := lastIdx downto 1 do
      pDgt[idx] := 2 * dgtBase5[idx];
    pDgt[0] := 2 * dgtBase5[0]+1;
  end;

  procedure CnvOddBase10(lastIdx:NativeInt);
  var
    pdgt : tpBaseType;
    idx: nativeint;
  begin
    pDgt := @dgtOddBase10[0];
    //make all odd
    for idx := lastIdx downto 1 do
      pDgt[idx] := 2 * dgtBase5[idx] + 1;
    //but the lowest even
    pDgt[0] := 2 * dgtBase5[0];
  end;

  function IncDgtBase5:NativeUint;
  // increment n base 5 until resulting sum of split number
  // can't end in 5
  var
    pb: tpBaseType;
    n,i: nativeint;
  begin
    result := 0;
    repeat
      repeat
        //increment Base5
        pb:= @dgtBase5[0];
         i := 0;
        repeat
          n := pb[i] + 1;
          if n < 5 then
          begin
            pb[i] := n;
            break;
          end;
          pb[i] := 0;
          Inc(i);
        until False;

        if HighIdx < i then
        begin
          HighIdx := i;
          pb[i] := 0;
        end;

        if result < i then
          result := i;

        n := dgtORMask[i+1];
        while i >= 0 do
        begin
          n := n OR (1 shl pb[i]);
          dgtORMask[i]:= n;
          if n = 31 then
            break;
          dec(i);
        end;

        if HighIdx<4 then
          break;

        if (n <> 31) OR (i=0) then
          break;
        //Now there are all digits are used at digit i ( not in last pos)
        //this will always lead to a number ending in 5-> not prime
        //so going on with a number that will change the used below i to highest digit
        //to create an overflow of the next number, to change the digits
        dec(i);
        repeat
          pb[i] := 4;
          dgtORMask[i]:= 31;
          dec(i);
        until i < 0;

      until false;
      if HighIdx<4 then
        break;

      n := dgtORMask[1];
      //ending in 5. base10(base5) for odd 1+4(0,2),3+2(1,1),5+0(2,0)
      i := pb[0];
      if i <= 2 then
      begin
        i := 1 shl (2-i);
      end
      else
      Begin
        //ending in 5 7+8(3,4),9+6(4,3)
        i := 1 shl (4-i);
        n := n shr 3;
      end;
      if (i AND n) = 0 then
        BREAK;
    until false;
  end;

  procedure CheckMagn(var dgtBase10: tBase);
  //split number into sum of all "partitions" of digits
  //check if sum is always prime
  //1234 -> 1+234,12+34 ;123+4
  var
    LowSplitNum : tSplitNum;
    i,fac,n: NativeInt;
    isMagn : boolean;
  Begin
    n := 0;
    fac := 1;
    For i := 0 to HighIdx-1 do
    begin
      n := fac*dgtBase10[i]+n;
      fac *=10;
      LowSplitNum[HighIdx-1-i] := n;
    end;

    n := 0;
    fac := HighIdx;
    isMagn := true;

    For i := 0 to fac-1 do
    begin
      //n = HighSplitNum[i]
      n := n*10+dgtBase10[fac-i];
      LowSplitNum[i] += n;
      if LowSplitNum[i]<=MAXLIMIT then
      begin
        isMagn := isMagn AND (pPrimes0[LowSplitNum[i]] = 0);
        if NOT(isMagn) then
          EXIT;
      end;
    end;
    {$IFDEF USE_GMP}
    For i := 0 to fac-1 do
    begin
      n := LowSplitNum[i];
      if n >MAXLIMIT then
      Begin
//      IF NOT((n mod 30) in [1,7,11,13,17,19,23,29]) then    EXIT;
        mpz_set_ui(z,n);
        gmp_count +=1;
        isMagn := isMagn AND (mpz_probab_prime_p(z,1) >0);
        if NOT(isMagn) then
          EXIT;
      end;
    end;

   {$ENDIF}
    //insert magnanimous numbers
    num := Base10toNum(dgtBase10);
    MagList[MagIdx] := num;
    inc(MagIdx);
  end;

function Run(StartDgtCount:byte):Uint64;
var
  lastIdx: NativeInt;
begin
  result := 0;
  HighIdx := StartDgtCount;// 7 start with 7 digits
  LastIdx := HighIdx;
  repeat
    if dgtBase5[HighIdx] <> 0 then
    Begin
      CnvEvenBase10(LastIdx);
      CheckMagn(dgtEvenBase10);
    end;
    CnvOddBase10(LastIdx);
    CheckMagn(dgtOddBase10);
    inc(result);
    //output for still running every 16.22 Mio
    IF result AND (1 shl 22-1) = 0 then
      OutSol(result);

    lastIdx := IncDgtBase5;
  until HighIdx > MAXHIGHIDX;

end;

BEGIN
  {$IFDEF USE_GMP}mpz_init_set_ui(z,0);{$ENDIF}
  T0 := Gettickcount64;
  InitPrimes;
  T0 -= Gettickcount64;
  writeln('getting primes ',-T0 / 1000: 0: 3, ' s');
  T0 := Gettickcount64;
  fillchar(dgtBase5,SizeOf(dgtBase5),#0);
  fillchar(dgtEvenBase10,SizeOf(dgtEvenBase10),#0);
  fillchar(dgtOddBase10,SizeOf(dgtOddBase10),#0);
//Magnanimous Numbers that can not be found by this algorithm
  MagIdx := 0;
  MagList[MagIdx] := 1;inc(MagIdx);
  MagList[MagIdx] := 11;inc(MagIdx);
  MagList[MagIdx] := 20;inc(MagIdx);
  MagList[MagIdx] := 101;inc(MagIdx);
  MagList[MagIdx] := 1001;inc(MagIdx);
  //cant be checked easy for ending in 5
  MagList[MagIdx] := 40001;inc(MagIdx);
  {$IFDEF USE_GMP} mpz_init_set_ui(z,0);{$ENDIF}

  count := Run(0);

  writeln;
  CnvOddBase10(highIdx);
  writeln(MagIdx:5,count:12,Base10toNum(dgtOddBase10):18,
           (Gettickcount64-T0) / 1000: 10: 3, ' s');
  InsertSort(@MagList[0],0,MagIdx-1);

  {$IFDEF USE_GMP} mpz_clear(z);writeln('Count of gmp tests ',gmp_count);{$ENDIF}
  For cnt := 0 to MagIdx-1 do
    writeln(cnt+1:3,'   ',MagList[cnt]);
  {$IFDEF WINDOWS}
    readln;
  {$ENDIF}
end.


use strict;
use warnings;
use feature 'say';
use ntheory 'is_prime';

sub magnanimous {
    my($n) = @_;
    my $last;
    for my $c (1 .. length($n) - 1) {
        ++$last and last unless is_prime substr($n,0,$c) + substr($n,$c)
    }
    not $last;
}

my @M;
for ( my $i = 0, my $count = 0; $count < 400; $i++ ) {
    ++$count and push @M, $i if magnanimous($i);
}

say "First 45 magnanimous numbers\n".
    (sprintf "@{['%4d' x 45]}", @M[0..45-1]) =~ s/(.{60})/$1\n/gr;

say "241st through 250th magnanimous numbers\n" .
    join ' ', @M[240..249];

say "\n391st through 400th magnanimous numbers\n".
    join ' ', @M[390..399];


with javascript_semantics
function magnanimous(integer n)
    integer p = 1, r = 0
    while n>=10 do
        r += remainder(n,10)*p
        n = floor(n/10)
        if not is_prime(n+r) then return false end if
        p *= 10
    end while
    return true
end function

sequence mag = {}
integer n = 0
while length(mag)<400 do
    if magnanimous(n) then mag &= n end if
    n += 1
end while
puts(1,"First 45 magnanimous numbers: ") pp(mag[1..45],{pp_Indent,30,pp_IntCh,false,pp_Maxlen,100})
printf(1,"magnanimous numbers[241..250]: %v\n", {mag[241..250]})
printf(1,"magnanimous numbers[391..400]: %v\n", {mag[391..400]})


(de **Mod (X Y N)
   (let M 1
      (loop
         (when (bit? 1 Y)
            (setq M (% (* M X) N)) )
         (T (=0 (setq Y (>> 1 Y)))
            M )
         (setq X (% (* X X) N)) ) ) )
(de isprime (N)
   (cache '(NIL) N
      (if (== N 2)
         T
         (and
            (> N 1)
            (bit? 1 N)
            (let (Q (dec N)  N1 (dec N)  K 0  X)
               (until (bit? 1 Q)
                  (setq
                     Q (>> 1 Q)
                     K (inc K) ) )
               (catch 'composite
                  (do 16
                     (loop
                        (setq X
                           (**Mod
                              (rand 2 (min (dec N) 1000000000000))
                              Q
                              N ) )
                        (T (or (=1 X) (= X N1)))
                        (T
                           (do K
                              (setq X (**Mod X 2 N))
                              (when (=1 X) (throw 'composite))
                              (T (= X N1) T) ) )
                        (throw 'composite) ) )
                  (throw 'composite T) ) ) ) ) ) )
(de numbers (N)
   (let (P 10  Q N)
      (make
         (until (> 10 Q)
            (link
               (+
                  (setq Q (/ N P))
                  (% N P) ) )
            (setq P (* P 10)) ) ) ) )
(de ismagna (N)
   (or
      (> 10 N)
      (fully isprime (numbers N)) ) )
(let (C 0  N 0 Lst)
   (setq Lst
      (make
         (until (== C 401)
            (when (ismagna N)
               (link N)
               (inc 'C) )
            (inc 'N) ) ) )
   (println (head 45 Lst))
   (println (head 10 (nth Lst 241)))
   (println (head 10 (nth Lst 391))) )


100H: /* FIND SOME MAGNANIMOUS NUMBERS - THOSE WHERE INSERTING '+' BETWEEN  */
   /* ANY TWO OF THE DIGITS AND EVALUATING THE SUM RESULTS IN A PRIME       */
   BDOS: PROCEDURE( FN, ARG ); /* CP/M BDOS SYSTEM CALL */
      DECLARE FN BYTE, ARG ADDRESS;
      GOTO 5;
   END BDOS;
   PRINT$CHAR:   PROCEDURE( C ); DECLARE C BYTE; CALL BDOS( 2, C );    END;
   PRINT$STRING: PROCEDURE( S ); DECLARE S ADDRESS; CALL BDOS( 9, S ); END;
   PRINT$NL:     PROCEDURE; CALL PRINT$STRING( .( 0DH, 0AH, '$' ) );   END;
   PRINT$NUMBER: PROCEDURE( N );
      DECLARE N ADDRESS;
      DECLARE V ADDRESS, N$STR( 6 ) BYTE, W BYTE;
      V = N;
      W = LAST( N$STR );
      N$STR( W ) = '$';
      N$STR( W := W - 1 ) = '0' + ( V MOD 10 );
      DO WHILE( ( V := V / 10 ) > 0 );
         N$STR( W := W - 1 ) = '0' + ( V MOD 10 );
      END;
      IF N < 100 THEN DO;
         IF N < 10 THEN CALL PRINT$CHAR( ' ' );
         CALL PRINT$CHAR( ' ' );
      END;
      CALL PRINT$STRING( .N$STR( W ) );
   END PRINT$NUMBER;
   /* INTEGER SQUARE ROOT: BASED ON THE ONE IN THE PL/M FROBENIUS NUMBERS */
   SQRT: PROCEDURE( N )ADDRESS;
      DECLARE ( N, X0, X1 ) ADDRESS;
      IF N <= 3 THEN DO;
          IF N = 0 THEN X0 = 0; ELSE X0 = 1;
          END;
      ELSE DO;
         X0 = SHR( N, 1 );
         DO WHILE( ( X1 := SHR( X0 + ( N / X0 ), 1 ) ) < X0 );
            X0 = X1;
         END;
      END;
      RETURN X0;
   END SQRT;

   DECLARE MAGNANIMOUS (251)ADDRESS; /* MAGNANIMOUS NUMBERS              */
   DECLARE FALSE           LITERALLY '0';
   DECLARE TRUE            LITERALLY '0FFH';
   /* TO FIND MAGNANIMOUS NUMBERS UP TO 30$000, WE NEED TO FIND PRIMES   */
   /* UP TO 9$999 + 9 = 10$008                                           */
   DECLARE MAX$PRIME       LITERALLY '10$008';
   DECLARE DCL$PRIME       LITERALLY '10$009';
   /* SIEVE THE PRIMES TO MAX$PRIME */
   DECLARE ( I, S ) ADDRESS;
   DECLARE PRIME ( DCL$PRIME )BYTE;
   PRIME( 1 ) = FALSE; PRIME( 2 ) = TRUE;
   DO I = 3 TO LAST( PRIME ) BY 2; PRIME( I ) = TRUE;  END;
   DO I = 4 TO LAST( PRIME ) BY 2; PRIME( I ) = FALSE; END;
   DO I = 3 TO SQRT( MAX$PRIME );
      IF PRIME( I ) THEN DO;
         DO S = I * I TO LAST( PRIME ) BY I + I;PRIME( S ) = FALSE; END;
      END;
   END;

   /* FIND THE MAGNANIMOUS NUMBERS                                       */
   FIND$MAGNANIMOUS: PROCEDURE;
      DECLARE ( D1, D2, D3, D4, D5
              , D12, D123, D1234
              , D23, D234, D2345
              , D34, D345, D45
              ) ADDRESS;
      DECLARE M$COUNT ADDRESS; /* COUNT OF MAGNANIMOUS NUMBERS FOUND     */
      STORE$MAGNANIMOUS: PROCEDURE( N )BYTE;
         DECLARE N ADDRESS;
         M$COUNT = M$COUNT + 1;
         IF M$COUNT <= LAST( MAGNANIMOUS ) THEN MAGNANIMOUS( M$COUNT ) = N;
         RETURN M$COUNT <= LAST( MAGNANIMOUS );
      END STORE$MAGNANIMOUS;

      M$COUNT = 0;
      /* 1 DIGIT MAGNANIMOUS NUMBERS                                        */
      DO D1 = 0 TO 9; IF NOT STORE$MAGNANIMOUS( D1 ) THEN RETURN; END;
      /* 2 DIGIT MAGNANIMOUS NUMBERS                                        */
      DO D1 = 1 TO 9;
         DO D2 = 0 TO 9;
            IF PRIME( D1 + D2 ) THEN DO;
               IF NOT STORE$MAGNANIMOUS( ( D1 * 10 ) + D2 ) THEN RETURN;
            END;
         END;
      END;
      /* 3 DIGIT MAGNANIMOUS NUMBERS                                        */
      DO D1 = 1 TO 9;
         DO D23 = 0 TO 99;
            IF PRIME( D1 + D23 ) THEN DO;
               D3  = D23 MOD 10;
               D12 = ( D1 * 10 ) + ( D23 / 10 );
               IF PRIME( D12 + D3 ) THEN DO;
                  IF NOT STORE$MAGNANIMOUS( ( D12 * 10 ) + D3 ) THEN RETURN;
               END;
            END;
         END;
      END;
      /* 4 DIGIT MAGNANIMOUS NUMBERS                                     */
      DO D12 = 10 TO 99;
         DO D34 = 0 TO 99;
            IF PRIME( D12 + D34 ) THEN DO;
               D123 = ( D12 * 10 ) + ( D34 / 10 );
               D4   = D34 MOD 10;
               IF PRIME( D123 + D4 ) THEN DO;
                  D1   = D12 / 10;
                  D234 = ( ( D12 MOD 10 ) * 100 ) + D34;
                  IF PRIME( D1 + D234 ) THEN DO;
                     IF NOT STORE$MAGNANIMOUS( ( D12 * 100 ) + D34 )
                        THEN RETURN;
                  END;
               END;
            END;
         END;
      END;
      /* 5 DIGIT MAGNANIMOUS NUMBERS UP TO 30$000                        */
      DO D12 = 10 TO 30;
         DO D345 = 0 TO 999;
            IF PRIME( D12 + D345 ) THEN DO;
               D123 = ( D12 * 10 ) + ( D345 / 100 );
               D45  = D345 MOD 100;
               IF PRIME( D123 + D45 ) THEN DO;
                  D1234 = ( D123 * 10 ) + ( D45 / 10 );
                  D5    = D45 MOD 10;
                  IF PRIME( D1234 + D5 ) THEN DO;
                     D1    = D12 / 10;
                     D2345 = ( ( D12 MOD 10 ) * 1000 ) + D345;
                     IF PRIME( D1 + D2345 ) THEN DO;
                        IF NOT STORE$MAGNANIMOUS( ( D12 * 1000 ) + D345 )
                           THEN RETURN;
                     END;
                  END;
               END;
            END;
         END;
      END;
   END FIND$MAGNANIMOUS ;

   CALL FIND$MAGNANIMOUS;
   DO I = 1 TO LAST( MAGNANIMOUS );
      IF I = 1 THEN DO;
         CALL PRINT$STRING( .'MAGNANIMOUS NUMBERS 1-45:$' ); CALL PRINT$NL;
         CALL PRINT$NUMBER( MAGNANIMOUS( I ) );
         END;
      ELSE IF I < 46 THEN DO;
         IF I MOD 15 = 1 THEN CALL PRINT$NL; ELSE CALL PRINT$CHAR( ' ' );
         CALL PRINT$NUMBER( MAGNANIMOUS( I ) );
         END;
      ELSE IF I = 241 THEN DO;
         CALL PRINT$NL;
         CALL PRINT$STRING( .'MAGANIMOUS NUMBERS 241-250:$' ); CALL PRINT$NL;
         CALL PRINT$NUMBER( MAGNANIMOUS( I ) );
         END;
      ELSE IF I > 241 AND I <= 250 THEN DO;
         CALL PRINT$CHAR( ' ' );
         CALL PRINT$NUMBER( MAGNANIMOUS( I ) );
      END;
   END;
   CALL PRINT$NL;
EOF


my @magnanimous = lazy flat ^10, (10 .. 1001).map( {
    my int $last;
    (1 ..^ .chars).map: -> \c { $last = 1 and last unless (.substr(0,c) + .substr(c)).is-prime }
    next if $last;
    $_
} ),

(1002 .. ∞).map: {
     # optimization for numbers > 1001; First and last digit can not both be even or both be odd
    next if (.substr(0,1) + .substr(*-1)) %% 2;
    my int $last;
    (1 ..^ .chars).map: -> \c { $last = 1 and last unless (.substr(0,c) + .substr(c)).is-prime }
    next if $last;
    $_
}

put 'First 45 magnanimous numbers';
put @magnanimous[^45]».fmt('%3d').batch(15).join: "\n";

put "\n241st through 250th magnanimous numbers";
put @magnanimous[240..249];

put "\n391st through 400th magnanimous numbers";
put @magnanimous[390..399];


/*REXX pgm finds/displays magnanimous #s  (#s with a inserted + sign to sum to a prime).*/
parse arg bet.1 bet.2 bet.3 highP .              /*obtain optional arguments from the CL*/
if bet.1=='' | bet.1==","  then bet.1=   1..45   /* "      "         "   "   "     "    */
if bet.2=='' | bet.2==","  then bet.2= 241..250  /* "      "         "   "   "     "    */
if bet.3=='' | bet.3==","  then bet.3= 391..400  /* "      "         "   "   "     "    */
if highP=='' | highP==","  then highP=  1000000  /* "      "         "   "   "     "    */
call genP                                        /*gen primes up to  highP  (1 million).*/

     do j=1  for 3                               /*process three magnanimous "ranges".  */
     parse var   bet.j   LO  '..'  HI            /*obtain the first range (if any).     */
     if HI==''  then HI= LO                      /*Just a single number?   Then use LO. */
     if HI==0   then iterate                     /*Is HI a zero?   Then skip this range.*/
     finds= 0;                             $=    /*#:  magnanimous # cnt;  $:  is a list*/
                do k=0  until finds==HI          /* [↓]  traipse through the number(s). */
                if \magna(k)  then iterate       /*Not magnanimous?  Then skip this num.*/
                finds= finds + 1                 /*bump the magnanimous number count.   */
                if finds>=LO  then $= $ k        /*In range►  Then add number ──► $ list*/
                end   /*k*/
     say
     say center(' 'LO       "──►"       HI       'magnanimous numbers ',  126, "─")
     say strip($)
     end        /*j*/
exit 0                                           /*stick a fork in it,  we're all done. */
/*──────────────────────────────────────────────────────────────────────────────────────*/
magna: procedure expose @. !.; parse arg x 1 L 2 '' -1 R  /*obtain #,  1st & last digit.*/
       len= length(x);       if len==1  then return 1     /*one digit #s are magnanimous*/
       if x>1001  then if L//2 == R//2  then return 0     /*Has parity?  Not magnanimous*/
                do  s= 1  for  len-1                      /*traipse thru #, inserting + */
                parse var  x   y  +(s)  z;   sum= y + z   /*parse 2 parts of #, sum 'em.*/
                if !.sum  then iterate                    /*Is sum prime? So far so good*/
                          else return 0                   /*Nope?  Then not magnanimous.*/
                end   /*s*/
       return 1                                  /*Pass all the tests, it's magnanimous.*/
/*──────────────────────────────────────────────────────────────────────────────────────*/
genP: @.1=2; @.2=3; @.3=5; @.4=7; @.5=11; @.6=13   /*assign low primes; # primes.*/
      !.= 0; !.2=1; !.3=1; !.5=1; !.7=1; !.11=1; !.13=1   /*   "   semaphores to   "    */
                           #= 6;  sq.#= @.# ** 2          /*# primes so far;  P squared.*/
        do [email protected].#+4  by 2  to highP; parse var j '' -1 _; if _==5  then iterate /*÷ by 5?*/
        if j// 3==0  then iterate;   if j// 7==0  then iterate    /*÷ by 3?;     ÷ by 7?*/
        if j//11==0  then iterate                                 /*"  " 11?     " " 13?*/
                do k=6  while sq.k<=j            /*divide by some generated odd primes. */
                if j//@.k==0  then iterate j     /*Is J divisible by  P?  Then not prime*/
                end   /*k*/                      /* [↓]  a prime  (J)  has been found.  */
        #= #+1;   @.#= j;   sq.#= j*j;   !.j= 1  /*bump #Ps; P──►@.assign P; P^2; P flag*/
        end     /*j*/;                 return


load "stdlib.ring"
n = -1
sum = 0
magn = []

while sum < 45
      n = n + 1
      if n < 10
         add(magn,n)
         sum = sum + 1
      else
         nStr = string(n)
         check = 0
         for m = 1 to len(nStr)-1
             nr1 = number(left(nStr,m))
             nr2 = number(right(nStr,len(nStr)-m))
             nr3 = nr1 + nr2
             if not isprime(nr3)
                check = 1
             ok
          next
          if check = 0
             add(magn,n)
             sum = sum + 1
          ok
       ok
end

see "Magnanimous numbers 1-45:" + nl
showArray(magn)

n = -1
sum = 0
magn = []

while sum < 250
      n = n + 1
      if n < 10
         sum = sum + 1
      else
         nStr = string(n)
         check = 0
         for m = 1 to len(nStr)-1
             nr1 = number(left(nStr,m))
             nr2 = number(right(nStr,len(nStr)-m))
             nr3 = nr1 + nr2
             if not isprime(nr3)
                check = 1
             ok
          next
          if check = 0
             sum = sum + 1
          ok
          if check = 0 and sum > 240 and sum < 251
             add(magn,n)
          ok
       ok
end

see nl
see "Magnanimous numbers 241-250:" + nl
showArray(magn)

func showArray array
     txt = ""
     see "["
     for n = 1 to len(array)
         txt = txt + array[n] + ","
     next
     txt = left(txt,len(txt)-1)
     txt = txt + "]"
     see txt


require "prime"

magnanimouses = Enumerator.new do |y|
  (0..).each {|n| y << n if (1..n.digits.size-1).all? {|k| n.divmod(10**k).sum.prime?} }
end

puts "First 45 magnanimous numbers:"
puts magnanimouses.first(45).join(' ')

puts "\n241st through 250th magnanimous numbers:"
puts magnanimouses.first(250).last(10).join(' ')

puts "\n391st through 400th magnanimous numbers:"
puts magnanimouses.first(400).last(10).join(' ')


fn is_prime(n: u32) -> bool {
    if n < 2 {
        return false;
    }
    if n % 2 == 0 {
        return n == 2;
    }
    if n % 3 == 0 {
        return n == 3;
    }
    let mut p = 5;
    while p * p <= n {
        if n % p == 0 {
            return false;
        }
        p += 2;
        if n % p == 0 {
            return false;
        }
        p += 4;
    }
    true
}

fn is_magnanimous(n: u32) -> bool {
    let mut p: u32 = 10;
    while n >= p {
        if !is_prime(n % p + n / p) {
            return false;
        }
        p *= 10;
    }
    true
}

fn main() {
    let mut m = (0..).filter(|x| is_magnanimous(*x)).take(400);
    println!("First 45 magnanimous numbers:");
    for (i, n) in m.by_ref().take(45).enumerate() {
        if i > 0 && i % 15 == 0 {
            println!();
        }
        print!("{:3} ", n);
    }
    println!("\n\n241st through 250th magnanimous numbers:");
    for n in m.by_ref().skip(195).take(10) {
        print!("{} ", n);
    }
    println!("\n\n391st through 400th magnanimous numbers:");
    for n in m.by_ref().skip(140) {
        print!("{} ", n);
    }
    println!();
}


func is_magnanimous(n) {
    1..n.ilog10 -> all {|k|
        sum(divmod(n, k.ipow10)).is_prime
    }
}

say "First 45 magnanimous numbers:"
say is_magnanimous.first(45).join(' ')

say "\n241st through 250th magnanimous numbers:"
say is_magnanimous.first(250).last(10).join(' ')

say "\n391st through 400th magnanimous numbers:"
say is_magnanimous.first(400).last(10).join(' ')


import Foundation

func isPrime(_ n: Int) -> Bool {
    if n < 2 {
        return false
    }
    if n % 2 == 0 {
        return n == 2
    }
    if n % 3 == 0 {
        return n == 3
    }
    var p = 5
    while p * p <= n {
        if n % p == 0 {
            return false
        }
        p += 2
        if n % p == 0 {
            return false
        }
        p += 4
    }
    return true
}

func isMagnanimous(_ n: Int) -> Bool {
    var p = 10;
    while n >= p {
        if !isPrime(n % p + n / p) {
            return false
        }
        p *= 10
    }
    return true
}

let m = (0...).lazy.filter{isMagnanimous($0)}.prefix(400);
print("First 45 magnanimous numbers:");
for (i, n) in m.prefix(45).enumerated() {
    if i > 0 && i % 15 == 0 {
        print()
    }
    print(String(format: "%3d", n), terminator: " ")
}
print("\n\n241st through 250th magnanimous numbers:");
for n in m.dropFirst(240).prefix(10) {
    print(n, terminator: " ")
}
print("\n\n391st through 400th magnanimous numbers:");
for n in m.dropFirst(390) {
    print(n, terminator: " ")
}
print()


Imports System, System.Console

Module Module1

    Dim np As Boolean()

    Sub ms(ByVal lmt As Long)
        np = New Boolean(CInt(lmt)) {} : np(0) = True : np(1) = True
        Dim n As Integer = 2, j As Integer = 1 : While n < lmt
            If Not np(n) Then
                Dim k As Long = CLng(n) * n
                While k < lmt : np(CInt(k)) = True : k += n : End While
            End If : n += j : j = 2 : End While
    End Sub

    Function is_Mag(ByVal n As Integer) As Boolean
        Dim res, rm As Integer, p As Integer = 10
        While n >= p
            res = Math.DivRem(n, p, rm)
            If np(res + rm) Then Return False
            p = p * 10 : End While : Return True
    End Function

    Sub Main(ByVal args As String())
        ms(100_009) : Dim mn As String = " magnanimous numbers:"
        WriteLine("First 45{0}", mn) : Dim l As Integer = 0, c As Integer = 0
        While c < 400 : If is_Mag(l) Then
            c += 1 : If c <= 45 OrElse (c > 240 AndAlso c <= 250) OrElse c > 390 Then Write(If(c <= 45, "{0,4} ", "{0,8:n0} "), l)
            If c < 45 AndAlso c Mod 15 = 0 Then WriteLine()
            If c = 240 Then WriteLine(vbLf & vbLf & "241st through 250th{0}", mn)
            If c = 390 Then WriteLine(vbLf & vbLf & "391st through 400th{0}", mn)
        End If : l += 1 : End While
    End Sub
End Module


import "/fmt" for Conv, Fmt
import "/math" for Int

var isMagnanimous = Fn.new { |n|
    if (n < 10) return true
    var p = 10
    while (true) {
        var q = (n/p).floor
        var r = n % p
        if (!Int.isPrime(q + r)) return false
        if (q < 10) break
        p = p * 10
    }
    return true
}

var listMags = Fn.new { |from, thru, digs, perLine|
    if (from < 2) {
        System.print("\nFirst %(thru) magnanimous numbers:")
    } else {
        System.print("\n%(Conv.ord(from)) through %(Conv.ord(thru)) magnanimous numbers:")
    }
    var i = 0
    var c = 0
    while (c < thru) {
        if (isMagnanimous.call(i)) {
            c = c + 1
            if (c >= from) {
                System.write(Fmt.d(digs, i) + " ")
                if (c % perLine == 0) System.print()
            }
        }
        i = i + 1
    }
}

listMags.call(1, 45, 3, 15)
listMags.call(241, 250, 1, 10)
listMags.call(391, 400, 1, 10)


import std.stdio, std.range, std.algorithm;

/// Rotate uint left.
uint rol(in uint x, in uint nBits) @safe pure nothrow @nogc {
    return (x << nBits) | (x >> (32 - nBits));
}

alias Nibble = ubyte; // 4 bits used.
alias SBox = immutable Nibble[16][8];

private bool _validateSBox(in SBox data) @safe pure nothrow @nogc {
    foreach (const ref row; data)
        foreach (ub; row)
            if (ub >= 16) // Verify it's a nibble.
                return false;
    return true;
}

struct GOST(s...) if (s.length == 1 && s[0]._validateSBox) {
    private static generate(ubyte k)() @safe pure nothrow {
        return k87.length.iota
               .map!(i=> (s[0][k][i >> 4] << 4) | s[0][k - 1][i & 0xF])
               .array;
    }

    private uint[2] buffer;
    private static immutable ubyte[256] k87 = generate!7,
                                        k65 = generate!5,
                                        k43 = generate!3,
                                        k21 = generate!1;

    // Endianess problems?
    private static uint f(in uint x) pure nothrow @nogc @safe {
        immutable uint y = (k87[(x >> 24) & 0xFF] << 24) |
                           (k65[(x >> 16) & 0xFF] << 16) |
                           (k43[(x >>  8) & 0xFF] <<  8) |
                            k21[ x        & 0xFF];
        return rol(y, 11);
    }

    // This performs only a step of the encoding.
    public void mainStep(in uint[2] input, in uint key)
    pure nothrow @nogc @safe {
        buffer[0] = f(key + input[0]) ^ input[1];
        buffer[1] = input[0];
    }
}

void main() {
    // S-boxes used by the Central Bank of Russian Federation:
    // http://en.wikipedia.org/wiki/GOST_28147-89
    // (This is a matrix of nibbles).
    enum SBox cbrf = [
      [ 4, 10,  9,  2, 13,  8,  0, 14,  6, 11,  1, 12,  7, 15,  5,  3],
      [14, 11,  4, 12,  6, 13, 15, 10,  2,  3,  8,  1,  0,  7,  5,  9],
      [ 5,  8,  1, 13, 10,  3,  4,  2, 14, 15, 12,  7,  6,  0,  9, 11],
      [ 7, 13, 10,  1,  0,  8,  9, 15, 14,  4,  6, 12, 11,  2,  5,  3],
      [ 6, 12,  7,  1,  5, 15, 13,  8,  4, 10,  9, 14,  0,  3, 11,  2],
      [ 4, 11, 10,  0,  7,  2,  1, 13,  3,  6,  8,  5,  9, 12, 15, 14],
      [13, 11,  4,  1,  3, 15,  5,  9,  0, 10, 14,  7,  6,  8,  2, 12],
      [ 1, 15, 13,  0,  5,  7, 10,  4,  9,  2,  3, 14,  6, 11,  8, 12]];

    GOST!cbrf g;

    // Example from the talk page (bytes swapped for endianess):
    immutable uint[2] input = [0x_04_3B_04_21, 0x_04_32_04_30];
    immutable uint key = 0x_E2_C1_04_F9;

    g.mainStep(input, key);
    writefln("%(%08X %)", g.buffer);
}


 ПЕР
   Ключ: РЯД 8 ИЗ ЦЕЛ;
   ТаблицаЗамен: РЯД 8, 16 ИЗ ЯЧЦЕЛ;

 ЗАДАЧА БеззнСлжПоМод32(ч1, ч2: ЦЕЛ): ЦЕЛ;
 ПЕР
    память1, память2: ШИРЦЕЛ;
    результат: ЦЕЛ;
 УКАЗ
   память1 := 0; ОБХОД.Образ(ОБХОД.ПолучитьАдрес(ч1), ОБХОД.ПолучитьАдрес(память1), 4);
   память2 := 0; ОБХОД.Образ(ОБХОД.ПолучитьАдрес(ч2), ОБХОД.ПолучитьАдрес(память2), 4);
   УВЕЛИЧИТЬ(память1, память2);
   ОБХОД.Образ(ОБХОД.ПолучитьАдрес(память1), ОБХОД.ПолучитьАдрес(результат), 4);
   ВОЗВРАТ результат
 КОН БеззнСлжПоМод32;

 ЗАДАЧА ИсклИЛИ(ч1, ч2: ЦЕЛ): ЦЕЛ;
 УКАЗ
   ВОЗВРАТ ОБХОД.Значение(ЦЕЛ, ОБХОД.Значение(МНОЖ, ч1) / ОБХОД.Значение(МНОЖ, ч2))
 КОН ИсклИЛИ;

 ЗАДАЧА Замена(стр: ЯЧЦЕЛ; яч: ОБХОД.Ячейка): ЯЧЦЕЛ;
 ПЕР
   п1, п2, п3: ЦЕЛ; результат: ЯЧЦЕЛ;
 УКАЗ
   п1 := 0; п2 := 0; ОБХОД.Образ(ОБХОД.ПолучитьАдрес(яч), ОБХОД.ПолучитьАдрес(п1), 1);
   п1 := Асм.Сдвиг(п1, 4); ОБХОД.Образ(ОБХОД.ПолучитьАдрес(п1), ОБХОД.ПолучитьАдрес(п2), 1);
   п2 := Асм.Сдвиг(п2, -4); п1 := Асм.Сдвиг(п1, -8);
   п3 := ТаблицаЗамен[стр*2, п2] + Асм.Сдвиг(ТаблицаЗамен[стр*2+1, п1], 4);
   ОБХОД.Образ(ОБХОД.ПолучитьАдрес(п3), ОБХОД.ПолучитьАдрес(результат), 1);
   ВОЗВРАТ результат
 КОН Замена;

 ЗАДАЧА ОсновнойШаг(N: ШИРЦЕЛ; X: ЦЕЛ): ШИРЦЕЛ;
 ПЕР
   N1, N2, S: ЦЕЛ;
   сч: ЯЧЦЕЛ;
   ячейка: ЯЧЦЕЛ;
   результат: ШИРЦЕЛ;
 УКАЗ
   ОБХОД.Образ(ОБХОД.ПолучитьАдрес(N), ОБХОД.ПолучитьАдрес(N1), 4);
   ОБХОД.Образ(ОБХОД.ПолучитьАдрес(N)+4, ОБХОД.ПолучитьАдрес(N2), 4);
   S := БеззнСлжПоМод32(N1, X);
   ОТ сч := 0 ДО 3 ВЫП
     ОБХОД.Образ(ОБХОД.ПолучитьАдрес(S)+сч, ОБХОД.ПолучитьАдрес(ячейка), 1);
     ячейка := Замена(сч, ячейка);
     ОБХОД.Образ(ОБХОД.ПолучитьАдрес(ячейка), ОБХОД.ПолучитьАдрес(S)+сч, 1)
   КОН;
   S := Асм.Вращение(S, 11);
   S := ИсклИЛИ(S, N2);
   N2 := N1; N1 := S;
   ОБХОД.Образ(ОБХОД.ПолучитьАдрес(N1), ОБХОД.ПолучитьАдрес(результат), 4);
   ОБХОД.Образ(ОБХОД.ПолучитьАдрес(N2), ОБХОД.ПолучитьАдрес(результат)+4, 4);
   ВОЗВРАТ результат
 КОН ОсновнойШаг;


// version 1.1.4-3

fun Byte.toUInt()  = java.lang.Byte.toUnsignedInt(this)

fun Byte.toULong() = java.lang.Byte.toUnsignedLong(this)

fun Int.toULong()  = java.lang.Integer.toUnsignedLong(this)

val s = arrayOf(
    byteArrayOf( 4, 10,  9,  2, 13,  8,  0, 14,  6, 11,  1, 12,  7, 15,  5,  3),
    byteArrayOf(14, 11,  4, 12,  6, 13, 15, 10,  2,  3,  8,  1,  0,  7,  5,  9),
    byteArrayOf( 5,  8,  1, 13, 10,  3,  4,  2, 14, 15, 12,  7,  6,  0,  9, 11),
    byteArrayOf( 7, 13, 10,  1,  0,  8,  9, 15, 14,  4,  6, 12, 11,  2,  5,  3),
    byteArrayOf( 6, 12,  7,  1,  5, 15, 13,  8,  4, 10,  9, 14,  0,  3, 11,  2),
    byteArrayOf( 4, 11, 10,  0,  7,  2,  1, 13,  3,  6,  8,  5,  9, 12, 15, 14),
    byteArrayOf(13, 11,  4,  1,  3, 15,  5,  9,  0, 10, 14,  7,  6,  8,  2, 12),
    byteArrayOf( 1, 15, 13,  0,  5,  7, 10,  4,  9,  2,  3, 14,  6, 11,  8, 12)
)

class Gost(val sBox: Array<ByteArray>) {

    val k87 = ByteArray(256)
    val k65 = ByteArray(256)
    val k43 = ByteArray(256)
    val k21 = ByteArray(256)
    val enc = ByteArray(8)

    init {
        for (i in 0 until 256) {
            val j = i ushr 4
            val k = i and 15
            k87[i] = ((sBox[7][j].toUInt() shl 4) or sBox[6][k].toUInt()).toByte()
            k65[i] = ((sBox[5][j].toUInt() shl 4) or sBox[4][k].toUInt()).toByte()
            k43[i] = ((sBox[3][j].toUInt() shl 4) or sBox[2][k].toUInt()).toByte()
            k21[i] = ((sBox[1][j].toUInt() shl 4) or sBox[0][k].toUInt()).toByte()
        }
    }

    fun f(x: Int): Int {
        val y = (k87[(x ushr 24) and 255].toULong() shl 24) or
                (k65[(x ushr 16) and 255].toULong() shl 16) or
                (k43[(x ushr  8) and 255].toULong() shl  8) or
                (k21[ x and 255].toULong())
        return ((y shl 11) or (y ushr 21)).toInt()
    }

    fun u32(ba: ByteArray): Int =
        (ba[0].toULong() or
        (ba[1].toULong() shl 8) or
        (ba[2].toULong() shl 16) or
        (ba[3].toULong() shl 24)).toInt()

    fun b4(u: Int) {
        enc[0] = u.toByte()
        enc[1] = (u ushr  8).toByte()
        enc[2] = (u ushr 16).toByte()
        enc[3] = (u ushr 24).toByte()
    }

    fun mainStep(input: ByteArray, key: ByteArray) {
        val key32  = u32(key)
        val input1 = u32(input.sliceArray(0..3))
        val input2 = u32(input.sliceArray(4..7))
        val temp   = (key32.toULong() + input1.toULong()).toInt()
        b4(f(temp) xor input2)
        for (i in 0..3) enc[4 + i] = input[i]
    }
}

fun main(args: Array<String>) {
    val input = byteArrayOf(0x21, 0x04, 0x3B, 0x04, 0x30, 0x04, 0x32, 0x04)
    val key = byteArrayOf(0xF9.toByte(), 0x04, 0xC1.toByte(), 0xE2.toByte())
    val g = Gost(s)
    g.mainStep(input, key)
    for (b in g.enc) print("[%02X]".format(b))
    println()
}


ИП6	С/П	+	П6	ИП7	С/П	+	П7	ИПE	-
x>=0	14	П7	КИП6	ИП6	ИПE	-	x>=0	20	П6
8	П2	П3	2	П1	4	П0	0	П8	1
П9	КИП2	ИПB	/	[x]	ПA	Вх	{x}	ИПB	*
С/П	ИП9	*	ИП8	+	П8	ИП9	ИПB	*	П9
ИПA	L0	32	ИП8	КП3	L1	25	8	П0	ИП7
ПП	93	П1	ИП6	ПП	93	ИП5	+	П6	ИП1
ИП4	+	П7	ИП4	ИП6	С/П	П4	ИП5	ИП7	С/П
П5	ИП4	ИП6	П4	<->	П6	ИП5	ИП7	П5	<->
П7	БП	00	ИПC	/	[x]	КП0	Вx	{x}	ИПC
*	ИПD	*	В/О


#lang racket

(define k8 (bytes 14  4 13  1  2 15 11  8  3 10  6 12  5  9  0  7))
(define k7 (bytes 15  1  8 14  6 11  3  4  9  7  2 13 12  0  5 10))
(define k6 (bytes 10  0  9 14  6  3 15  5  1 13 12  7 11  4  2  8))
(define k5 (bytes  7 13 14  3  0  6  9 10  1  2  8  5 11 12  4 15))
(define k4 (bytes  2 12  4  1  7 10 11  6  8  5  3 15 13  0 14  9))
(define k3 (bytes 12  1 10 15  9  2  6  8  0 13  3  4 14  7  5 11))
(define k2 (bytes  4 11  2 14 15  0  8 13  3 12  9  7  5 10  6  1))
(define k1 (bytes 13  2  8  4  6 15 11  1 10  9  3 14  5  0 12  7))

(define (mk-k k2 k1)
  (list->bytes (for*/list ([i 16] [j 16]) (+ (* (bytes-ref k2 i) 16) (bytes-ref k1 j)))))

(define k87 (mk-k k8 k7))
(define k65 (mk-k k6 k5))
(define k43 (mk-k k4 k3))
(define k21 (mk-k k2 k1))

(define (f x)
  (define bs (integer->integer-bytes x 4 #f #f))
  (define x*
    (bitwise-and #xFFFFFFFF
                 (integer-bytes->integer
                  (bytes (bytes-ref k21 (bytes-ref bs 0))
                         (bytes-ref k43 (bytes-ref bs 1))
                         (bytes-ref k65 (bytes-ref bs 2))
                         (bytes-ref k87 (bytes-ref bs 3)))
                  #f #f)))
  (bitwise-ior (bitwise-and #xFFFFFFFF (arithmetic-shift x* 11))
               (arithmetic-shift x* (- 11 32))))


namespace eval ::GOST {
    proc tcl::mathfunc::k {a b} {
	variable ::GOST::replacementTable
	lindex $replacementTable $a $b
    }

    proc mainStep {textBlock idx key} {
	variable replacementTable
	lassign [lindex $textBlock $idx] N0 N1
	set S [expr {($N0 + $key) & 0xFFFFFFFF}]
	set newS 0
	for {set i 0} {$i < 4} {incr i} {
	    set cell [expr {$S >> ($i * 8) & 0xFF}]
	    incr newS [expr {
		(k($i*2, $cell%15) + k($i*2+1, $cell/16) * 16) << ($i * 8)
	    }]
	}
	set S [expr {((($newS << 11) + ($newS >> 21)) & 0xFFFFFFFF) ^ $N1}]
	lset textBlock $idx [list $S $N0]
	return $textBlock
    }
}


        .386
        .model  flat
        .code
_gost32 proc    near32
        public  _gost32
; The inner loop of a subroutine
; 1. Beginning of the cycle, and preservation of the old N1
iloop:  mov     EBP,EAX
; 2. Adding to the S key modulo 2^32
        add     EAX,[ESI] ; add the key
        add     ESI,4   ; the next element of the key.
; 3. Block-replace in the rotation of S by 8 bits to the left
REPT    3
        xlat            ; recoding byte
        ror     EAX,8   ; AL <- next byte
        add     EBX,100h; next node changes
ENDM
        xlat            ; recoding byte
        sub     EBX,300h; BX -> 1st node changes
; 4. Complete rotation of the S at 3 bits to the left
        rol     EAX,3
; 5. The calculation of the new values of N1,N2
        xor     EAX,EDX
        mov     EDX,EBP
; The completion of the inner loop
        loop    iloop
        ret
_gost32 endp
        end


-V LOG_10 = 2.302585092994

F build_oms(=s)
   I s % 2 == 0
      s++
   V q = [[0] * s] * s
   V p = 1
   V i = s I/ 2
   V j = 0

   L p <= (s * s)
      q[i][j] = p
      V ti = i + 1
      I ti >= s
         ti = 0
      V tj = j - 1
      I tj < 0
         tj = s - 1
      I q[ti][tj] != 0
         ti = i
         tj = j + 1
      i = ti
      j = tj
      p++

   R (q, s)

F build_sems(=s)
   I s % 2 == 1
      s++
   L s % 4 == 0
      s += 2
   V q = [[0] * s] * s
   V z = s I/ 2
   V b = z * z
   V c = 2 * b
   V d = 3 * b
   V o = build_oms(z)

   L(j) 0 .< z
      L(i) 0 .< z
         V a = o[0][i][j]
         q[i][j] = a
         q[i + z][j + z] = a + b
         q[i + z][j] = a + c
         q[i][j + z] = a + d

   V lc = z I/ 2
   V rc = lc
   L(j) 0 .< z
      L(i) 0 .< s
         I i < lc
         | i > s - rc
         | (i == lc & j == lc)
            I !(i == 0 & j == lc)
               swap(&q[i][j], &q[i][j + z])
   R (q, s)

F display(q)
   V s = q[1]
   print(" - #. x #.\n".format(s, s))
   V k = 1 + Int(floor(log(s * s) / :LOG_10))
   L(j) 0 .< s
      L(i) 0 .< s
         print(String(q[0][i][j]).zfill(k), end' ‘ ’)
      print()
   print(‘Magic sum: #.’.format(s * ((s * s) + 1) I/ 2))

print(‘Singly Even Magic Square’, end' ‘’)
display(build_sems(6))


*        Magic squares of singly even order - 21/04/2021
MAGSQSE  CSECT
         USING  MAGSQSE,R13        base register
         B      72(R15)            skip savearea
         DC     17F'0'             savearea
         SAVE   (14,12)            save previous context
         ST     R13,4(R15)         link backward
         ST     R15,8(R13)         link forward
         LR     R13,R15            set addressability
         LH     R2,N               n
         MH     R2,N               *n
         LA     R2,1(R2)           +1
         MH     R2,N               *n
         SRA    R2,1               /2
         STH    R2,MAGSUM          magsum=n*(n^2+1)/2
         LH     R2,N               n
         SRA    R2,1               /2
         STH    R2,ND              nd=n/2
         LH     R2,ND              n
         MH     R2,ND              *n
         STH    R2,ND2             nd2=nd^2
         LH     R2,N               n
         SH     R2,=H'2'           -2
         SRA    R2,2               /4
         STH    R2,LL              ll=(n-2)/4
         LH     R6,ND              nd
         SRA    R6,1               /2
         LA     R6,1(R6)           i=nd/2+1
         LA     R7,1               j=1
         LR     R5,R7              nr=1
         LH     R4,N               n
       IF    CH,R4,LT,=H'6' THEN   if n<6 then
         XPRNT  =C'Error: too small',16
         B      FIN                  stop
       ENDIF    ,                  endif
         LH     R2,N               n
         SH     R2,=H'2'           -2
         SRDA   R2,32              ~
         D      R2,=F'4'           /4
       IF   LTR,R2,NZ,R2 THEN      if mod(n-2,4)<>0 then
         XPRNT  =C'Error: not possible',19
         B      FIN                  stop
       ENDIF    ,                  endif
LOOP     EQU    *                  do loop --------------v
         LR     R1,R6                i
         LR     R2,R7                j
         BAL    R14,SQXY             [email protected](i,j)
         LH     R2,SQ(R1)            sq(i,j)
       IF   LTR,R2,Z,R2 THEN         if sq(i,j)=0 then
         STH    R5,SQ(R1)              sq(i,j)=nr             _A
         LR     R1,R6                  i
         AH     R1,ND                  +nd
         LR     R2,R7                  j
         AH     R2,ND                  +nd
         BAL    R14,SQXY               [email protected](i+nd,j+nd)
         LR     R3,R5                  nr
         AH     R3,ND2                 +nd2
         STH    R3,SQ(R1)              sq(i+nd,j+nd)=nr+nd2   _B
         LR     R1,R6                  i
         AH     R1,ND                  +nd
         LR     R2,R7                  j
         BAL    R14,SQXY               [email protected](i+nd,j)
         LH     R3,ND2                 nd2
         SLA    R3,1                   *2
         AR     R3,R5                  +nr
         STH    R3,SQ(R1)              sq(i+nd,j)=nr+nd2*2;   _C
         LR     R1,R6                  i
         LR     R2,R7                  j
         AH     R2,ND                  +nd
         BAL    R14,SQXY               [email protected](i,j+nd)
         LH     R3,ND2                 nd2
         MH     R3,=H'3'               *3
         AR     R3,R5                  +nr
         STH    R3,SQ(R1)              sq(i,j+nd)=nr+nd2*3;   _D
         LR     R2,R5                  nr
         LH     R0,ND                  nd
         SRDA   R2,32                  ~
         DR     R2,R0                  nr/nd
       IF   LTR,R2,Z,R2 THEN           if mod(nr,nd)=0 then
         LA     R7,1(R7)                 j=j+1
       ELSE     ,                      else
         LA     R6,1(R6)                 i=i+1
         BCTR   R7,0                     j=j-1
       ENDIF    ,                      endif
         LA     R5,1(R5)               nr=nr+1
       ENDIF    ,                    endif
       IF    CH,R6,GT,ND THEN        if i>nd then
         LA     R6,1                   i=1
         BAL    R12,SQIJ               r2=sq(i,j)
       DO WHILE=(LTR,R2,NZ,R2)         do while sq(i,j)<>0
         LA     R6,1(R6)                 i=i+1
         BAL    R12,SQIJ                 r2=sq(i,j)
       ENDDO    ,                      enddo
       ENDIF    ,                    endif
       IF    CH,R7,LT,=H'1' THEN     if j<1 then
         LH     R7,ND                  j=nd
         BAL    R12,SQIJ               r2=sq(i,j)
       DO WHILE=(LTR,R2,NZ,R2)         do while sq(i,j)<>0
         BCTR   R7,0                     j=j-1
         BAL    R12,SQIJ                 r2=sq(i,j)
       ENDDO    ,                      enddo
       ENDIF    ,                    endif
         CH     R5,ND2             nr>nd2
         BNH    LOOP               until nr>nd2 ---------^
         LA     R7,1               j=1 -- swap left side
       DO WHILE=(CH,R7,LE,ND)      do j=1 to nd
         LA     R6,1                 i=1
       DO WHILE=(CH,R6,LE,LL)        do i=1 to ll
         BAL    R12,SWAPIJ             swap sq(i,j),sq(i,j+nd)
         LA     R6,1(R6)               i++
       ENDDO    ,                    enddo i
         LA     R7,1(R7)             j++
       ENDDO    ,                  enddo j
         LH     R7,ND              nd
         SRA    R7,1               /2
         LA     R7,1(R7)           j=nd/2+1
         LA     R1,1               1
         LR     R2,R7              j
         BAL    R14,SQXY           [email protected](1,j)
         LR     R3,R1              [email protected](1,j)
         LA     R1,1               1
         LR     R2,R7              j
         AH     R2,ND              j+nd
         BAL    R14,SQXY           [email protected](1,j+nd)
         BAL    R14,SWAPXY         swap sq(1,j),sq(1,j+nd)
         LH     R1,LL              ll
         LA     R1,1(R1)           ll+1
         LR     R2,R7              j
         BAL    R14,SQXY           [email protected](ll+1,j)
         LR     R3,R1              [email protected](ll+1,j)
         LH     R1,LL              ll
         LA     R1,1(R1)           +1
         LR     R2,R7              j
         AH     R2,ND              +nd
         BAL    R14,SQXY           [email protected](ll+1,j+nd)
         BAL    R14,SWAPXY         swap sq(ll+1,j),sq(ll+1,j+nd)
         LH     R5,N               n
         SH     R5,LL              -ll
         LA     R5,2(R5)           r5=n-ll+2
         LA     R7,1               j=1 -- swap right side
       DO WHILE=(CH,R7,LE,ND)      do j=1 to nd
         LR     R6,R5                i=n-ll+2
       DO WHILE=(CH,R6,LE,N)         do i=n-ll+2 to n
         BAL    R12,SWAPIJ             swap sq(i,j),sq(i,j+nd)
         LA     R6,1(R6)               i++
       ENDDO    ,                    enddo i
         LA     R7,1(R7)             j++
       ENDDO    ,                  enddo j
         LA     R7,1               j=1  check columms and rows
       DO WHILE=(CH,R7,LE,N)       do j=1 to n
         SR     R4,R4                nr=0
         SR     R5,R5                nc=0
         LA     R6,1                 i=1
       DO WHILE=(CH,R6,LE,N)         do i=1 to n
         LR     R1,R6                  i
         LR     R2,R7                  j
         BAL    R14,SQXY               [email protected](i,j)
         AH     R4,SQ(R1)              nr=nr+sq(i,j)
         LR     R1,R7                  j
         LR     R2,R6                  i
         BAL    R14,SQXY               [email protected](j,i)
         AH     R5,SQ(R1)              nc=nc+sq(j,i)
         LA     R6,1(R6)               i++
       ENDDO    ,                    enddo i
       IF    CH,R4,NE,MAGSUM,OR,CH,R5,NE,MAGSUM THEN
         XPRNT  =C'Error: row/col value<>magsum',28
         B      FIN                    stop
       ENDIF    ,                    endif
         LA     R7,1(R7)             j++
       ENDDO    ,                  enddo j
         SR     R4,R4              nr=0
         SR     R5,R5              nc=0
         LA     R6,1               i=1
       DO WHILE=(CH,R6,LE,N)       do i=1 to n
         LR     R1,R6                i
         LR     R2,R6                i
         BAL    R14,SQXY             [email protected](i,i)
         AH     R4,SQ(R1)            nr=nr+sq(i,i)
         LH     R1,N                 n
         SR     R1,R6                n-i
         LA     R1,1(R1)             n-i+1
         LR     R2,R1                n-i+1
         BAL    R14,SQXY             [email protected](i,i)
         AH     R5,SQ(R1)            nc=nc+sq(n-i+1,n-i+1)
         LA     R6,1(R6)             i++
       ENDDO    ,                  enddo i
       IF    CH,R4,NE,MAGSUM,OR,CH,R5,NE,MAGSUM THEN
         XPRNT  =C'Error: diag value<>magsum',25
         B      FIN                  stop
       ENDIF    ,                  endif
         MVC    PG(31),=C'Single even magic square size: '
         LH     R1,N               n
         XDECO  R1,XDEC            edit n
         MVC    PG+31(3),XDEC+9    output n
         XPRNT  PG,34              print buffer
         MVC    PG(15),=C'The magic sum= '
         LH     R1,MAGSUM          magsum
         XDECO  R1,XDEC            edit magsum
         MVC    PG+15(4),XDEC+8    output magsum
         XPRNT  PG,19              print buffer
         LA     R7,1               j=1
       DO WHILE=(CH,R7,LE,N)       do j=1 to n
         MVC    PG,=CL120' '         clear buffer
         LA     R9,PG                @buffer
         LA     R6,1                 i=1
       DO WHILE=(CH,R6,LE,N)         do i=1 to n
         LR     R1,R6                  i
         LR     R2,R7                  j
         BAL    R14,SQXY               [email protected](i,i)
         LH     R2,SQ(R1)              sq(i,j)
         XDECO  R2,XDEC                edit sq(i,j)
         MVC    0(4,R9),XDEC+8         output  sq(i,j)
         LA     R9,4(R9)               @buffer+=4
         LA     R6,1(R6)               i++
       ENDDO    ,                    enddo i
         XPRNT  PG,L'PG              print buffer
         LA     R7,1(R7)             j++
       ENDDO    ,                  enddo j
FIN      L      R13,4(0,R13)       restore previous savearea pointer
         RETURN (14,12),RC=0       restore registers from calling save
SQIJ     CNOP   0,4                routine sq(i,j)
         LR     R1,R6              i
         LR     R2,R7              j
         BAL    R14,SQXY           [email protected](i,j)
         LH     R2,SQ(R1)          sq(i,j)
         BR     R12                return
SQXY     CNOP   0,4                routine sq(r1,r2)
         BCTR   R1,0               -1
         MH     R1,N               *n
         BCTR   R2,0               -1
         AR     R1,R2              (r1-1)*n+(r2-1)
         SLA    R1,1               *2 (H)
         BR     R14                return
SWAPIJ   CNOP   0,4                routine swap sq(i,j),sq(i,j+nd)
         LR     R1,R6              i
         LR     R2,R7              j
         BAL    R14,SQXY           [email protected](i,j)
         LR     R3,R1              [email protected](i,j)
         LR     R1,R6              i
         LR     R2,R7              j
         AH     R2,ND              +nd
         BAL    R14,SQXY           [email protected](i,j+nd)
         BAL    R14,SWAPXY         swap
         BR     R12                return
SWAPXY   CNOP   0,4                routine swap sq(r1),sq(r3)
         LH     R0,SQ(R3)          r0=sq(r3)
         LH     R2,SQ(R1)          r2=sq(r1)
         STH    R2,SQ(R3)          sq(r3)=r2
         STH    R0,SQ(R1)          sq(r1)=r0
         BR     R14                return
NN       EQU    6                  <== parameter (6,10,14,18,22,26,...)
N        DC     AL2(NN)            n
SQ       DC     (NN*NN)H'0'        array sq(n,n)
MAGSUM   DS     H                  magsum
ND       DS     H                  nd
ND2      DS     H                  nd2
LL       DS     H                  ll
PG       DC     CL120' '           buffer
XDEC     DS     CL12               temp for xdeco
         REGEQU
         END    MAGSQSE


   #include<stdlib.h>
   #include<ctype.h>
   #include<stdio.h>

   int** oddMagicSquare(int n) {
        if (n < 3 || n % 2 == 0)
            return NULL;

        int value = 0;
        int squareSize = n * n;
        int c = n / 2, r = 0,i;

        int** result = (int**)malloc(n*sizeof(int*));

		for(i=0;i<n;i++)
			result[i] = (int*)malloc(n*sizeof(int));

        while (++value <= squareSize) {
            result[r][c] = value;
            if (r == 0) {
                if (c == n - 1) {
                    r++;
                } else {
                    r = n - 1;
                    c++;
                }
            } else if (c == n - 1) {
                r--;
                c = 0;
            } else if (result[r - 1][c + 1] == 0) {
                r--;
                c++;
            } else {
                r++;
            }
        }
        return result;
    }

    int** singlyEvenMagicSquare(int n) {
        if (n < 6 || (n - 2) % 4 != 0)
            return NULL;

        int size = n * n;
        int halfN = n / 2;
        int subGridSize = size / 4, i;

        int** subGrid = oddMagicSquare(halfN);
        int gridFactors[] = {0, 2, 3, 1};
        int** result = (int**)malloc(n*sizeof(int*));

		for(i=0;i<n;i++)
			result[i] = (int*)malloc(n*sizeof(int));

        for (int r = 0; r < n; r++) {
            for (int c = 0; c < n; c++) {
                int grid = (r / halfN) * 2 + (c / halfN);
                result[r][c] = subGrid[r % halfN][c % halfN];
                result[r][c] += gridFactors[grid] * subGridSize;
            }
        }

        int nColsLeft = halfN / 2;
        int nColsRight = nColsLeft - 1;

        for (int r = 0; r < halfN; r++)
            for (int c = 0; c < n; c++) {
                if (c < nColsLeft || c >= n - nColsRight
                        || (c == nColsLeft && r == nColsLeft)) {

                    if (c == 0 && r == nColsLeft)
                        continue;

                    int tmp = result[r][c];
                    result[r][c] = result[r + halfN][c];
                    result[r + halfN][c] = tmp;
                }
            }

        return result;
    }

	int numDigits(int n){
		int count = 1;

		while(n>=10){
			n /= 10;
			count++;
		}

		return count;
	}

	void printMagicSquare(int** square,int rows){
		int i,j;

		for(i=0;i<rows;i++){
			for(j=0;j<rows;j++){
				printf("%*s%d",rows - numDigits(square[i][j]),"",square[i][j]);
			}
			printf("\n");
		}
		printf("\nMagic constant: %d ", (rows * rows + 1) * rows / 2);
	}

	int main(int argC,char* argV[])
	{
		int n;

		if(argC!=2||isdigit(argV[1][0])==0)
			printf("Usage : %s <integer specifying rows in magic square>",argV[0]);
		else{
			n = atoi(argV[1]);
			printMagicSquare(singlyEvenMagicSquare(n),n);
		}
		return 0;
	}


#include <iostream>
#include <sstream>
#include <iomanip>
using namespace std;

class magicSqr
{
public:
    magicSqr() { sqr = 0; }
    ~magicSqr() { if( sqr ) delete [] sqr; }

    void create( int d ) {
        if( sqr ) delete [] sqr;
        if( d & 1 ) d++;
        while( d % 4 == 0 ) { d += 2; }
        sz = d;
        sqr = new int[sz * sz];
        memset( sqr, 0, sz * sz * sizeof( int ) );
        fillSqr();
    }
    void display() {
        cout << "Singly Even Magic Square: " << sz << " x " << sz << "\n";
        cout << "It's Magic Sum is: " << magicNumber() << "\n\n";
        ostringstream cvr; cvr << sz * sz;
        int l = cvr.str().size();

        for( int y = 0; y < sz; y++ ) {
            int yy = y * sz;
            for( int x = 0; x < sz; x++ ) {
                cout << setw( l + 2 ) << sqr[yy + x];
            }
            cout << "\n";
        }
        cout << "\n\n";
    }
private:
    void siamese( int from, int to ) {
        int oneSide = to - from, curCol = oneSide / 2, curRow = 0, count = oneSide * oneSide, s = 1;

        while( count > 0 ) {
            bool done = false;
            while ( false == done ) {
                if( curCol >= oneSide ) curCol = 0;
                if( curRow < 0 ) curRow = oneSide - 1;
                done = true;
                if( sqr[curCol + sz * curRow] != 0 ) {
                    curCol -= 1; curRow += 2;
                    if( curCol < 0 ) curCol = oneSide - 1;
                    if( curRow >= oneSide ) curRow -= oneSide;

                    done = false;
                }
            }
            sqr[curCol + sz * curRow] = s;
            s++; count--; curCol++; curRow--;
        }
    }
    void fillSqr() {
        int n = sz / 2, ns = n * sz, size = sz * sz, add1 = size / 2, add3 = size / 4, add2 = 3 * add3;

        siamese( 0, n );

        for( int r = 0; r < n; r++ ) {
            int row = r * sz;
            for( int c = n; c < sz; c++ ) {
                int m = sqr[c - n + row];

                sqr[c + row] = m + add1;
                sqr[c + row + ns] = m + add3;
                sqr[c - n + row + ns] = m + add2;
            }
        }

        int lc = ( sz - 2 ) / 4, co = sz - ( lc - 1 );
        for( int r = 0; r < n; r++ ) {
            int row = r * sz;
            for( int c = co; c < sz; c++ ) {
                sqr[c + row] -= add3;
                sqr[c + row + ns] += add3;
            }
        }
        for( int r = 0; r < n; r++ ) {
            int row = r * sz;
            for( int c = 0; c < lc; c++ ) {
                int cc = c;
                if( r == lc ) cc++;
                sqr[cc + row] += add2;
                sqr[cc + row + ns] -= add2;
            }
        }
    }
    int magicNumber() { return sz * ( ( sz * sz ) + 1 ) / 2; }

    void inc( int& a ) { if( ++a == sz ) a = 0; }

    void dec( int& a ) { if( --a < 0 ) a = sz - 1; }

    bool checkPos( int x, int y ) { return( isInside( x ) && isInside( y ) && !sqr[sz * y + x] ); }

    bool isInside( int s ) { return ( s < sz && s > -1 ); }

    int* sqr;
    int sz;
};
int main( int argc, char* argv[] ) {
    magicSqr s; s.create( 6 );
    s.display();
    return 0;
}


import std.exception;
import std.stdio;

void main() {
    int n = 6;
    foreach (row; magicSquareSinglyEven(n)) {
        foreach (x; row) {
            writef("%2s ", x);
        }
        writeln();
    }
    writeln("\nMagic constant: ", (n * n + 1) * n / 2);
}

int[][] magicSquareOdd(const int n) {
    enforce(n >= 3 && n % 2 != 0, "Base must be odd and >2");

    int value = 0;
    int gridSize = n * n;
    int c = n / 2;
    int r = 0;

    int[][] result = new int[][](n, n);

    while(++value <= gridSize) {
        result[r][c] = value;
        if (r == 0) {
            if (c == n - 1) {
                r++;
            } else {
                r = n - 1;
                c++;
            }
        } else if (c == n - 1) {
            r--;
            c = 0;
        } else if (result[r - 1][c + 1] == 0) {
            r--;
            c++;
        } else {
            r++;
        }
    }

    return result;
}

int[][] magicSquareSinglyEven(const int n) {
    enforce(n >= 6 && (n - 2) % 4 == 0, "Base must be a positive multiple of four plus 2");

    int size = n * n;
    int halfN = n / 2;
    int subSquareSize = size / 4;

    int[][] subSquare = magicSquareOdd(halfN);
    int[] quadrantFactors = [0, 2, 3, 1];
    int[][] result = new int[][](n, n);

    for (int r = 0; r < n; r++) {
        for (int c = 0; c < n; c++) {
            int quadrant = (r / halfN) * 2 + (c / halfN);
            result[r][c] = subSquare[r % halfN][c % halfN];
            result[r][c] += quadrantFactors[quadrant] * subSquareSize;
        }
    }

    int nColsLeft = halfN / 2;
    int nColsRight = nColsLeft - 1;

    for (int r = 0; r < halfN; r++) {
        for (int c = 0; c < n; c++) {
            if (c < nColsLeft || c >= n - nColsRight
                || (c == nColsLeft && r == nColsLeft)) {
                if (c == 0 && r == nColsLeft) {
                    continue;
                }

                int tmp = result[r][c];
                result[r][c] = result[r + halfN][c];
                result[r + halfN][c] = tmp;
            }
        }
    }

    return result;
}


defmodule Magic_square do
  @lux  %{ L: [4, 1, 2, 3], U: [1, 4, 2, 3], X: [1, 4, 3, 2] }

  def singly_even(n) when rem(n-2,4)!=0, do: raise ArgumentError, "must be even, but not divisible by 4."
  def singly_even(2), do: raise ArgumentError, "2x2 magic square not possible."
  def singly_even(n) do
    n2 = div(n, 2)
    oms = odd_magic_square(n2)
    mat = make_lux_matrix(n2)
    square = synthesis(n2, oms, mat)
    IO.puts to_string(n, square)
    square
  end

  defp odd_magic_square(m) do       # zero beginning, it is 4 multiples.
    for i <- 0..m-1, j <- 0..m-1, into: %{},
        do: {{i,j}, (m*(rem(i+j+1+div(m,2),m)) + rem(i+2*j-5+2*m, m)) * 4}
  end

  defp make_lux_matrix(m) do
    center = div(m, 2)
    lux = List.duplicate(:L, center+1) ++ [:U] ++ List.duplicate(:X, m-center-2)
    (for {x,i} <- Enum.with_index(lux), j <- 0..m-1, into: %{}, do: {{i,j}, x})
    |> Map.put({center,   center}, :U)
    |> Map.put({center+1, center}, :L)
  end

  defp synthesis(m, oms, mat) do
    range = 0..m-1
    Enum.reduce(range, [], fn i,acc ->
      {row0, row1} = Enum.reduce(range, {[],[]}, fn j,{r0,r1} ->
                       x = oms[{i,j}]
                       [lux0, lux1, lux2, lux3] = @lux[mat[{i,j}]]
                       {[x+lux0, x+lux1 | r0], [x+lux2, x+lux3 | r1]}
                     end)
      [row0, row1 | acc]
    end)
  end

  defp to_string(n, square) do
    format = String.duplicate("~#{length(to_char_list(n*n))}w ", n) <> "\n"
    Enum.map_join(square, fn row ->
      :io_lib.format(format, row)
    end)
  end
end

Magic_square.singly_even(6)


' version 18-03-2016
' compile with: fbc -s console
' singly even magic square 6, 10, 14, 18...

Sub Err_msg(msg As String)
    Print msg
    Beep : Sleep 5000, 1 : Exit Sub
End Sub

Sub se_magicsq(n As UInteger, filename As String = "")

    ' filename <> "" then save square in a file
    ' filename can contain directory name
    ' if filename exist it will be overwriten, no error checking

    If n < 6 Then
        Err_msg( "Error: n is to small")
        Exit Sub
    End If

    If ((n -2) Mod 4) <> 0 Then
        Err_msg "Error: not possible to make singly" + _
                 " even magic square size " + Str(n)
        Exit Sub
    End If

    Dim As UInteger sq(1 To n, 1 To n)
    Dim As UInteger magic_sum = n * (n ^ 2 +1) \ 2
    Dim As UInteger sq_d_2 = n \ 2, q2 = sq_d_2 ^ 2
    Dim As UInteger l = (n -2) \ 4
    Dim As UInteger x = sq_d_2 \ 2 + 1, y = 1, nr = 1
    Dim As String frmt = String(Len(Str(n * n)) +1, "#")

    ' fill pattern A C
    '              D B
    ' main loop for creating magic square in section A
    ' the value for B,C and D is derived from A
    ' uses the FreeBASIC odd order magic square routine
    Do
        If sq(x, y) = 0 Then
            sq(x         , y         ) = nr          ' A
            sq(x + sq_d_2, y + sq_d_2) = nr + q2     ' B
            sq(x + sq_d_2, y         ) = nr + q2 * 2 ' C
            sq(x         , y + sq_d_2) = nr + q2 * 3 ' D
            If nr Mod sq_d_2 = 0 Then
                y += 1
            Else
                x += 1 : y -= 1
            End If
            nr += 1
        End If
        If x > sq_d_2 Then
            x = 1
            Do While sq(x,y) <> 0
                x += 1
            Loop
        End If
        If y < 1 Then
            y = sq_d_2
            Do While sq(x,y) <> 0
                y -= 1
            Loop
        End If
    Loop Until nr > q2

    ' swap left side
    For y = 1 To sq_d_2
        For x = 1 To l
            Swap sq(x, y), sq(x,y + sq_d_2)
        Next
    Next
    ' make indent
    y = (sq_d_2 \ 2) +1
    Swap sq(1, y), sq(1, y + sq_d_2) ' was swapped, restore to orignal value
    Swap sq(l +1, y), sq(l +1, y + sq_d_2)

    ' swap right side
    For y = 1 To sq_d_2
        For x = n - l +2 To n
            Swap sq(x, y), sq(x,y + sq_d_2)
        Next
    Next

    ' check columms and rows
    For y = 1 To n
        nr = 0 : l  = 0
        For x = 1 To n
            nr += sq(x,y)
            l  += sq(y,x)
        Next
        If nr <> magic_sum Or l <> magic_sum Then
            Err_msg "Error: value <> magic_sum"
            Exit Sub
        End If
    Next

    ' check diagonals
    nr = 0 : l = 0
    For x = 1 To n
        nr += sq(x, x)
        l  += sq(n - x +1, n - x +1)
    Next
    If nr <> magic_sum Or l <> magic_sum Then
        Err_msg "Error: value <> magic_sum"
        Exit Sub
    End If

    ' printing square's on screen bigger when
    ' n > 19 results in a wrapping of the line
    Print "Single even magic square size: "; n; "*"; n
    Print "The magic sum = "; magic_sum
    Print
    For y = 1 To n
        For x = 1 To n
            Print Using frmt; sq(x, y);
        Next
        Print
    Next

    ' output magic square to a file with the name provided
    If filename <> "" Then
        nr = FreeFile
        Open filename For Output As #nr
        Print #nr, "Single even magic square size: "; n; "*"; n
        Print #nr, "The magic sum = "; magic_sum
        Print #nr,
        For y = 1 To n
            For x = 1 To n
                Print #nr, Using frmt; sq(x,y);
            Next
            Print #nr,
        Next
        Close #nr
    End If

End Sub

' ------=< MAIN >=------

se_magicsq(6, "magicse6.txt") : Print

' empty keyboard buffer
While Inkey <> "" : Wend
Print : Print "hit any key to end program"
Sleep
End


package main

import (
    "fmt"
    "log"
)

func magicSquareOdd(n int) ([][]int, error) {
    if n < 3 || n%2 == 0 {
        return nil, fmt.Errorf("base must be odd and > 2")
    }
    value := 1
    gridSize := n * n
    c, r := n/2, 0
    result := make([][]int, n)

    for i := 0; i < n; i++ {
        result[i] = make([]int, n)
    }

    for value <= gridSize {
        result[r][c] = value
        if r == 0 {
            if c == n-1 {
                r++
            } else {
                r = n - 1
                c++
            }
        } else if c == n-1 {
            r--
            c = 0
        } else if result[r-1][c+1] == 0 {
            r--
            c++
        } else {
            r++
        }
        value++
    }
    return result, nil
}

func magicSquareSinglyEven(n int) ([][]int, error) {
    if n < 6 || (n-2)%4 != 0 {
        return nil, fmt.Errorf("base must be a positive multiple of 4 plus 2")
    }
    size := n * n
    halfN := n / 2
    subSquareSize := size / 4
    subSquare, err := magicSquareOdd(halfN)
    if err != nil {
        return nil, err
    }
    quadrantFactors := [4]int{0, 2, 3, 1}
    result := make([][]int, n)

    for i := 0; i < n; i++ {
        result[i] = make([]int, n)
    }

    for r := 0; r < n; r++ {
        for c := 0; c < n; c++ {
            quadrant := r/halfN*2 + c/halfN
            result[r][c] = subSquare[r%halfN][c%halfN]
            result[r][c] += quadrantFactors[quadrant] * subSquareSize
        }
    }

    nColsLeft := halfN / 2
    nColsRight := nColsLeft - 1

    for r := 0; r < halfN; r++ {
        for c := 0; c < n; c++ {
            if c < nColsLeft || c >= n-nColsRight ||
                (c == nColsLeft && r == nColsLeft) {
                if c == 0 && r == nColsLeft {
                    continue
                }
                tmp := result[r][c]
                result[r][c] = result[r+halfN][c]
                result[r+halfN][c] = tmp
            }
        }
    }
    return result, nil
}

func main() {
    const n = 6
    msse, err := magicSquareSinglyEven(n)
    if err != nil {
        log.Fatal(err)
    }
    for _, row := range msse {
        for _, x := range row {
            fmt.Printf("%2d ", x)
        }
        fmt.Println()
    }
    fmt.Printf("\nMagic constant: %d\n", (n*n+1)*n/2)
}


import qualified Data.Map.Strict as M
import Data.List (transpose, intercalate)
import Data.Maybe (fromJust, isJust)
import Control.Monad (forM_)
import Data.Monoid ((<>))

magic :: Int -> [[Int]]
magic n = mapAsTable ((4 * n) + 2) (hiResMap n)

-- Order of square -> sequence numbers keyed by cartesian coordinates
hiResMap :: Int -> M.Map (Int, Int) Int
hiResMap n =
  let mapLux = luxMap n
      mapSiam = siamMap n
  in M.fromList $
     foldMap
       (\(xy, n) ->
           luxNums xy (fromJust (M.lookup xy mapLux)) ((4 * (n - 1)) + 1))
       (M.toList mapSiam)

-- LUX table coordinate -> L|U|X -> initial number -> 4 numbered coordinates
luxNums :: (Int, Int) -> Char -> Int -> [((Int, Int), Int)]
luxNums xy lux n =
  zipWith (\x d -> (x, n + d)) (hiRes xy) $
  case lux of
    'L' -> [3, 0, 1, 2]
    'U' -> [0, 3, 1, 2]
    'X' -> [0, 3, 2, 1]
    _ -> [0, 0, 0, 0]

-- Size of square -> integers keyed by coordinates -> rows of integers
mapAsTable :: Int -> M.Map (Int, Int) Int -> [[Int]]
mapAsTable nCols xyMap =
  let axis = [0 .. nCols - 1]
  in fmap (fromJust . flip M.lookup xyMap) <$>
     (axis >>= \y -> [axis >>= \x -> [(x, y)]])

-- Dimension of LUX table -> LUX symbols keyed by coordinates
luxMap :: Int -> M.Map (Int, Int) Char
luxMap n =
  (M.fromList . concat) $
  zipWith
    (\y xs -> (zipWith (\x c -> ((x, y), c)) [0 ..] xs))
    [0 ..]
    (luxPattern n)

-- LUX dimension -> square of L|U|X cells with two mixed rows
luxPattern :: Int -> [String]
luxPattern n =
  let d = (2 * n) + 1
      [ls, us] = replicate n <$> "LU"
      [lRow, xRow] = replicate d <$> "LX"
  in replicate n lRow <> [ls <> ('U' : ls)] <> [us <> ('L' : us)] <>
     replicate (n - 1) xRow

-- Highest zero-based index of grid -> Siamese indices keyed by coordinates
siamMap :: Int -> M.Map (Int, Int) Int
siamMap n =
  let uBound = (2 * n)
      sPath uBound sMap (x, y) n =
        let newMap = M.insert (x, y) n sMap
        in if y == uBound && x == quot uBound 2
             then newMap
             else sPath uBound newMap (nextSiam uBound sMap (x, y)) (n + 1)
  in sPath uBound (M.fromList []) (n, 0) 1

-- Highest index of square -> Siam xys so far -> xy -> next xy coordinate
nextSiam :: Int -> M.Map (Int, Int) Int -> (Int, Int) -> (Int, Int)
nextSiam uBound sMap (x, y) =
  let alt (a, b)
        | a > uBound && b < 0 = (uBound, 1) -- Top right corner ?
        | a > uBound = (0, b) -- beyond right edge ?
        | b < 0 = (a, uBound) -- above top edge ?
        | isJust (M.lookup (a, b) sMap) = (a - 1, b + 2) -- already filled ?
        | otherwise = (a, b) -- Up one, right one.
  in alt (x + 1, y - 1)

-- LUX cell coordinate -> four coordinates at higher resolution
hiRes :: (Int, Int) -> [(Int, Int)]
hiRes (x, y) =
  let [col, row] = (* 2) <$> [x, y]
      [col1, row1] = succ <$> [col, row]
  in [(col, row), (col1, row), (col, row1), (col1, row1)]

-- TESTS ----------------------------------------------------------------------
checked :: [[Int]] -> (Int, Bool)
checked square = (h, all (h ==) t)
  where
    diagonals = fmap (flip (zipWith (!!)) [0 ..]) . ((:) <*> (return . reverse))
    h:t = sum <$> square <> transpose square <> diagonals square

table :: String -> [[String]] -> [String]
table delim rows =
  let justifyRight c n s = drop (length s) (replicate n c <> s)
  in intercalate delim <$>
     transpose
       ((fmap =<< justifyRight ' ' . maximum . fmap length) <$> transpose rows)

main :: IO ()
main =
  forM_ [1, 2, 3] $
  \n -> do
    let test = magic n
    putStrLn $ unlines (table " " (fmap show <$> test))
    print $ checked test
    putStrLn ""


odd =: i:@<[email protected]: |."0 1&|:^:2 >:@[email protected],~
t =: ((*: * [email protected]:) +"0 2 odd)@-:
l =: (f=:$~ # , #)@((<. , >.)@%&4 # (1: , 0:))
sh =: <:@-: * (bn=:-: # 2:) #: (2: ^ <[email protected]%&4)
lm =: sh |."0 1  l
rm =: [email protected] #: <:@(2: ^ <:@<[email protected]%&4)
a =: (([email protected] * {[email protected]) + lm * {:@t)
b =: (([email protected] * 1&{@t) + rm * 2&{@t)
c =: ((rm * 1&{@t) + [email protected] * 2&{@t)
d =: ((lm * {[email protected]) + [email protected] * {:@t)
m =: (a ,"1 c) , d ,"1 b


public class MagicSquareSinglyEven {

    public static void main(String[] args) {
        int n = 6;
        for (int[] row : magicSquareSinglyEven(n)) {
            for (int x : row)
                System.out.printf("%2s ", x);
            System.out.println();
        }
        System.out.printf("\nMagic constant: %d ", (n * n + 1) * n / 2);
    }

    public static int[][] magicSquareOdd(final int n) {
        if (n < 3 || n % 2 == 0)
            throw new IllegalArgumentException("base must be odd and > 2");

        int value = 0;
        int gridSize = n * n;
        int c = n / 2, r = 0;

        int[][] result = new int[n][n];

        while (++value <= gridSize) {
            result[r][c] = value;
            if (r == 0) {
                if (c == n - 1) {
                    r++;
                } else {
                    r = n - 1;
                    c++;
                }
            } else if (c == n - 1) {
                r--;
                c = 0;
            } else if (result[r - 1][c + 1] == 0) {
                r--;
                c++;
            } else {
                r++;
            }
        }
        return result;
    }

    static int[][] magicSquareSinglyEven(final int n) {
        if (n < 6 || (n - 2) % 4 != 0)
            throw new IllegalArgumentException("base must be a positive "
                    + "multiple of 4 plus 2");

        int size = n * n;
        int halfN = n / 2;
        int subSquareSize = size / 4;

        int[][] subSquare = magicSquareOdd(halfN);
        int[] quadrantFactors = {0, 2, 3, 1};
        int[][] result = new int[n][n];

        for (int r = 0; r < n; r++) {
            for (int c = 0; c < n; c++) {
                int quadrant = (r / halfN) * 2 + (c / halfN);
                result[r][c] = subSquare[r % halfN][c % halfN];
                result[r][c] += quadrantFactors[quadrant] * subSquareSize;
            }
        }

        int nColsLeft = halfN / 2;
        int nColsRight = nColsLeft - 1;

        for (int r = 0; r < halfN; r++)
            for (int c = 0; c < n; c++) {
                if (c < nColsLeft || c >= n - nColsRight
                        || (c == nColsLeft && r == nColsLeft)) {

                    if (c == 0 && r == nColsLeft)
                        continue;

                    int tmp = result[r][c];
                    result[r][c] = result[r + halfN][c];
                    result[r + halfN][c] = tmp;
                }
            }

        return result;
    }
}


function oddmagicsquare(order)
    if iseven(order)
        order += 1
    end
    q = zeros(Int, (order, order))
    p = 1
    i = div(order, 2) + 1
    j = 1
    while p <= order * order
        q[i, j] = p
        ti = (i + 1 > order) ? 1 : i + 1
        tj = (j - 1 < 1) ? order : j - 1
        if q[ti, tj] != 0
            ti = i
            tj = j + 1
        end
        i = ti
        j = tj
        p = p + 1
    end
    q, order
end

function singlyevenmagicsquare(order)
    if isodd(order)
        order += 1
    end
    if order % 4 == 0
        order += 2
    end
    q = zeros(Int, (order, order))
    z = div(order, 2)
    b = z * z
    c = 2 * b
    d = 3 * b
    sq, ord = oddmagicsquare(z)

    for j in 1:z, i in 1:z
        a = sq[i, j]
        q[i, j] = a
        q[i + z, j + z] = a + b
        q[i + z, j] = a + c
        q[i, j + z] = a + d
    end
    lc = div(z, 2)
    rc = lc - 1
    for j in 1:z, i in 1:order
        if i <= lc || i > order - rc || (i == lc && j == lc)
            if i != 0 || j != lc + 1
                t = q[i, j]
                q[i, j] = q[i, j + z]
                q[i, j + z] = t
            end
        end
    end
    q, order
end

function check(q)
    side = size(q)[1]
    sums = Vector{Int}()
    for n in 1:side
        push!(sums, sum(q[n, :]))
        push!(sums, sum(q[:, n]))
    end
    println(all(x->x==sums[1], sums) ?
        "Checks ok: all sides add to $(sums[1])." : "Bad sum.")
end

function display(q)
    r, c = size(q)
    for i in 1:r, j in 1:c
        nstr = lpad(string(q[i, j]), 4)
        print(j % c > 0 ? nstr : "$nstr\n")
    end
end

for o in (6, 10)
    println("\nWith order $o:")
    msq = singlyevenmagicsquare(o)[1]
    display(msq)
    check(msq)
end


// version 1.0.6

fun magicSquareOdd(n: Int): Array<IntArray> {
    if (n < 3 || n % 2 == 0)
         throw IllegalArgumentException("Base must be odd and > 2")

    var value = 0
    val gridSize = n * n
    var c = n / 2
    var r = 0
    val result = Array(n) { IntArray(n) }
    while (++value <= gridSize) {
        result[r][c] = value
        if (r == 0) {
            if (c == n - 1) r++
            else {
                r = n - 1
                c++
            }
        }
        else if (c == n - 1) {
            r--
            c = 0
        }
        else if (result[r - 1][c + 1] == 0) {
            r--
            c++
        }
        else r++
    }
    return result
}

fun magicSquareSinglyEven(n: Int): Array<IntArray> {
    if (n < 6 || (n - 2) % 4 != 0)
        throw IllegalArgumentException("Base must be a positive multiple of 4 plus 2")

    val size = n * n
    val halfN = n / 2
    val subSquareSize = size / 4
    val subSquare = magicSquareOdd(halfN)
    val quadrantFactors = intArrayOf(0, 2, 3, 1)
    val result = Array(n) { IntArray(n) }
    for (r in 0 until n)
        for (c in 0 until n) {
            val quadrant = r / halfN * 2  + c / halfN
            result[r][c] = subSquare[r % halfN][c % halfN]
            result[r][c] += quadrantFactors[quadrant] * subSquareSize
        }
    val nColsLeft = halfN / 2
    val nColsRight = nColsLeft - 1
    for (r in 0 until halfN)
        for (c in 0 until n)
            if (c < nColsLeft || c >= n - nColsRight || (c == nColsLeft && r == nColsLeft)) {
                if (c == 0 && r == nColsLeft) continue
                val tmp = result[r][c]
                result[r][c] = result[r + halfN][c]
                result[r + halfN][c] = tmp
            }
    return result
}

fun main(args: Array<String>) {
    val n = 6
    for (ia in magicSquareSinglyEven(n)) {
        for (i in ia) print("%2d  ".format(i))
        println()
    }
    println("\nMagic constant ${(n * n + 1) * n / 2}")
}


import sequtils, strutils

type Square = seq[seq[int]]

func magicSquareOdd(n: Positive): Square =
  ## Build a magic square of odd order.

  assert n >= 3 and (n and 1) != 0, "base must be odd and greater than 2."
  result = newSeqWith(n, newSeq[int](n))

  var
    r = 0
    c = n div 2
    value = 0

  while value < n * n:
    inc value
    result[r][c] = value
    if r == 0:
      if c == n - 1:
        inc r
      else:
        r = n - 1
        inc c
    elif c == n - 1:
      dec r
      c = 0
    elif result[r - 1][c + 1] == 0:
      dec r
      inc c
    else:
      inc r

func magicSquareSinglyEven(n: int): Square =
  ## Build a magic square of singly even order.

  assert n >= 6 and ((n - 2) and 3) == 0, "base must be a positive multiple of 4 plus 2."
  result = newSeqWith(n, newSeq[int](n))

  let
    halfN = n div 2
    subSquareSize = n * n div 4
    subSquare = magicSquareOdd(halfN)

  const QuadrantFactors = [0, 2, 3, 1]

  for r in 0..<n:
    for c in 0..<n:
      let quadrant = r div halfN * 2 + c div halfN
      result[r][c] = subSquare[r mod halfN][c mod halfN] + QuadrantFactors[quadrant] * subSquareSize

  let
    nColsLeft = halfN div 2
    nColsRight = nColsLeft - 1

  for r in 0..<halfN:
    for c in 0..<n:
      if c < nColsLeft or c >= n - nColsRight or (c == nColsLeft and r == nColsLeft):
        if c != 0 or r != nColsLeft:
          swap result[r][c], result[r + halfN][c]

func `$`(square: Square): string =
  ## Return the string representation of a magic square.
  let length = len($(square.len * square.len))
  for row in square:
    result.add row.mapIt(($it).align(length)).join(" ") & '\n'

when isMainModule:
  let n = 6
  echo magicSquareSinglyEven(n)
  echo "Magic constant = ", n * (n * n + 1) div 2