Magic squares of odd order: Difference between revisions

m
(Updated to work with Nim 1.4. Removed the '^' function.)
Line 1,833:
Encoding the traditional [[wp:Siamese_method|'Siamese' method]]
 
<lang haskell>import{-# qualifiedLANGUAGE Data.Map.StrictTupleSections as M#-}
 
import Control.Monad (forM_)
import Data.MaybeList (isJustintercalate, fromJusttranspose)
import qualified Data.ListMap.Strict (transpose,as intercalate)M
import Data.Maybe (fromJust, isJust)
 
magic :: Int -> [[Int]]
magic = mapAsTable <*> siamMap
 
-- SIAMESE METHOD FUNCTIONS ------------------------------------- SIAMESE METHOD FUNCTIONS ---------------
 
-- Highest zero-based index of grid -> 'Siamese' indices keyed by coordinates
-- 'Siamese' indices keyed by coordinates
siamMap :: Int -> M.Map (Int, Int) Int
siamMap n =
if| odd n = go n
| then let hotherwise = quot nM.fromList 2[]
where
uBound = n - 1
go n = sPath uBound (M.fromList []) sPath(quot uBound sMap (x2, y0) h =1
where
let newMap = M.insert (x, y) h sMap
h in if y == uBound && x == quot uBoundn 2
uBound = n - then newMap1
sPath uBound sMap (x, y) h else sPath=
let newMap = M.insert (x, y) h uBoundsMap
in if y == uBound && x == quot uBound newMap2
then (nextSiam uBound sMap (x, y))newMap
(h + 1)else
in sPath uBound (M.fromList []) (quot uBound 2, 0) 1sPath
uBound = n - 1 uBound
else M.fromList []
newMap
(nextSiam uBound sMap (x, y))
let newMap = M.insert (x,succ yh) h sMap
 
-- Highest index of square -> Siam xys so far -> xy -> next xy coordinate
-- 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) --< beyond0 right= edge(uBound, ?1)
| b < 0 = (a, uBound) -- abovebeyond topright edge ?
| isJust (M.lookup (a, b)> sMap)uBound = (a - 10, b + 2) -- already filled ?
-- above top edge ?
| b < 0 = (a, uBound)
-- already filled ?
| isJust (M.lookup (a, b) sMap) = (a - 1, b + 2)
| otherwise = (a, b) -- Up one, right one.
in alt (x + 1, y - 1)
 
-- DISPLAY AND TEST FUNCTIONS ------------------------------------ DISPLAY AND TEST FUNCTIONS --------------
 
-- Size of square -> integers keyed by coordinates -> rows of integers
-- -> 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 >>= \xy -> [(x, y)] <$> axis])
 
checked :: [[Int]] -> (Int, Bool)
checked square =
let diagonals =
fmap (flip (zipWith (!!)) [0 ..]) . ((:) <*> (return . reverse))
. ( (:)
h:t = sum <$> square ++ transpose square ++ diagonals square
<*> (return . reverse)
in (h, all (h ==) t)
)
h : t =
sum <$> square
h:t = sum <$> square ++ transpose square ++ diagonals square
<> diagonals square
in (h, all (h ==) t)
 
table :: String -> [[String]] -> [String]
table delim rows =
let justifyRight c n s = drop (length s) (replicate n c ++ s)
drop
in intercalate delim <$>
transpose (length s)
(replicate n c <> s)
((fmap =<< justifyRight ' ' . maximum . fmap length) <$> transpose rows)
in intercalate delim <$>
<$> transpose
( (fmap =<< justifyRight ' ' . maximum . fmap length) <$> transpose rows)
<$> transpose rows
)
 
main :: IO ()
main =
forM_ [3, 5, 7] $
\n -> do
let test = magic n
putStrLn $ unlines (table " " (fmap show <$> test))
print $ checked test
putStrLn ""</lang>
{{Out}}
<pre>8 1 6
9,655

edits