Skip to main content
Added syntax highlighting
Source Link
{- stack
     --install-ghc
     exec ghci
     --package lens
-}

module Main where

import Control.Lens
import Data.List.Lens
import Debug.Trace
import Text.Printf
import Prelude hiding (Left, Right)

data Direction = Up | Left | Down | Right

data Location = Location Int Int

type Grid = [[Int]]

main = printClockwise 25

printClockwise :: Int -> IO ()
printClockwise n = putStrLn $ concatMap printRow grid
  where
    grid = walk directions center 1 emptyGrid
    emptyGrid = replicate sq (take sq (repeat 0))
    printRow row = concatMap (printf "%4s" . show) row ++ "\n"
    -- Ex. for a 5x5 spiral the start location is (2,2)
    center = Location half half
    half = floor $ (fromIntegral sq) / 2
    -- This will return all directions we should walk through the spiral in.
    -- Something like [Right, Down, Left, Left, Up, Up, Right, Right, Right]
    directions = concatMap (\(direction, steps) -> take steps $ repeat direction) (zip directionOrder steps)
    directionOrder = cycle [Right, Down, Left, Up]
    -- Ex. for a spiral up to 25, the steps are 1, 1, 2, 2, 3, 3, 4, 4, 5
    steps = concatMap (take 2 . repeat) [1 .. sq - 1] <> [sq]
    -- Assume the input is a perfect square of an odd number
    sq = ceiling $ sqrt (fromIntegral n)

walk :: [Direction] -> Location -> Int -> Grid -> Grid
walk (dir : dirs) loc@(Location x y) current grid = do
  let grid' = grid & (ix y . ix x) .~ current
  let loc' = moveLocation dir loc
  walk dirs loc' (current + 1) grid'
walk [] _ _ numbers = numbers

moveLocation Down (Location x y) = Location (x) (y + 1)
moveLocation Right (Location x y) = Location (x + 1) (y)
moveLocation Left (Location x y) = Location (x -1) (y)
moveLocation Up (Location x y) = Location (x) (y - 1)

#!/usr/bin/env stack
{- stack
     --install-ghc
     exec ghci
     --package lens
-}

module Main where

import Control.Lens
import Data.List.Lens
import Debug.Trace
import Text.Printf
import Prelude hiding (Left, Right)

data Direction = Up | Left | Down | Right

data Location = Location Int Int

type Grid = [[Int]]

main = printClockwise 25

printClockwise :: Int -> IO ()
printClockwise n = putStrLn $ concatMap printRow grid
  where
    grid = walk directions center 1 emptyGrid
    emptyGrid = replicate sq (take sq (repeat 0))
    printRow row = concatMap (printf "%4s" . show) row ++ "\n"
    -- Ex. for a 5x5 spiral the start location is (2,2)
    center = Location half half
    half = floor $ (fromIntegral sq) / 2
    -- This will return all directions we should walk through the spiral in.
    -- Something like [Right, Down, Left, Left, Up, Up, Right, Right, Right]
    directions = concatMap (\(direction, steps) -> take steps $ repeat direction) (zip directionOrder steps)
    directionOrder = cycle [Right, Down, Left, Up]
    -- Ex. for a spiral up to 25, the steps are 1, 1, 2, 2, 3, 3, 4, 4, 5
    steps = concatMap (take 2 . repeat) [1 .. sq - 1] <> [sq]
    -- Assume the input is a perfect square of an odd number
    sq = ceiling $ sqrt (fromIntegral n)

walk :: [Direction] -> Location -> Int -> Grid -> Grid
walk (dir : dirs) loc@(Location x y) current grid = do
  let grid' = grid & (ix y . ix x) .~ current
  let loc' = moveLocation dir loc
  walk dirs loc' (current + 1) grid'
walk [] _ _ numbers = numbers

moveLocation Down (Location x y) = Location (x) (y + 1)
moveLocation Right (Location x y) = Location (x + 1) (y)
moveLocation Left (Location x y) = Location (x -1) (y)
moveLocation Up (Location x y) = Location (x) (y - 1)
{- stack
     --install-ghc
     exec ghci
     --package lens
-}

module Main where

import Control.Lens
import Data.List.Lens
import Debug.Trace
import Text.Printf
import Prelude hiding (Left, Right)

data Direction = Up | Left | Down | Right

data Location = Location Int Int

type Grid = [[Int]]

main = printClockwise 25

printClockwise :: Int -> IO ()
printClockwise n = putStrLn $ concatMap printRow grid
  where
    grid = walk directions center 1 emptyGrid
    emptyGrid = replicate sq (take sq (repeat 0))
    printRow row = concatMap (printf "%4s" . show) row ++ "\n"
    -- Ex. for a 5x5 spiral the start location is (2,2)
    center = Location half half
    half = floor $ (fromIntegral sq) / 2
    -- This will return all directions we should walk through the spiral in.
    -- Something like [Right, Down, Left, Left, Up, Up, Right, Right, Right]
    directions = concatMap (\(direction, steps) -> take steps $ repeat direction) (zip directionOrder steps)
    directionOrder = cycle [Right, Down, Left, Up]
    -- Ex. for a spiral up to 25, the steps are 1, 1, 2, 2, 3, 3, 4, 4, 5
    steps = concatMap (take 2 . repeat) [1 .. sq - 1] <> [sq]
    -- Assume the input is a perfect square of an odd number
    sq = ceiling $ sqrt (fromIntegral n)

walk :: [Direction] -> Location -> Int -> Grid -> Grid
walk (dir : dirs) loc@(Location x y) current grid = do
  let grid' = grid & (ix y . ix x) .~ current
  let loc' = moveLocation dir loc
  walk dirs loc' (current + 1) grid'
walk [] _ _ numbers = numbers

moveLocation Down (Location x y) = Location (x) (y + 1)
moveLocation Right (Location x y) = Location (x + 1) (y)
moveLocation Left (Location x y) = Location (x -1) (y)
moveLocation Up (Location x y) = Location (x) (y - 1)

#!/usr/bin/env stack
{- stack
     --install-ghc
     exec ghci
     --package lens
-}

module Main where

import Control.Lens
import Data.List.Lens
import Debug.Trace
import Text.Printf
import Prelude hiding (Left, Right)

data Direction = Up | Left | Down | Right

data Location = Location Int Int

type Grid = [[Int]]

main = printClockwise 25

printClockwise :: Int -> IO ()
printClockwise n = putStrLn $ concatMap printRow grid
  where
    grid = walk directions center 1 emptyGrid
    emptyGrid = replicate sq (take sq (repeat 0))
    printRow row = concatMap (printf "%4s" . show) row ++ "\n"
    -- Ex. for a 5x5 spiral the start location is (2,2)
    center = Location half half
    half = floor $ (fromIntegral sq) / 2
    -- This will return all directions we should walk through the spiral in.
    -- Something like [Right, Down, Left, Left, Up, Up, Right, Right, Right]
    directions = concatMap (\(direction, steps) -> take steps $ repeat direction) (zip directionOrder steps)
    directionOrder = cycle [Right, Down, Left, Up]
    -- Ex. for a spiral up to 25, the steps are 1, 1, 2, 2, 3, 3, 4, 4, 5
    steps = concatMap (take 2 . repeat) [1 .. sq - 1] <> [sq]
    -- Assume the input is a perfect square of an odd number
    sq = ceiling $ sqrt (fromIntegral n)

walk :: [Direction] -> Location -> Int -> Grid -> Grid
walk (dir : dirs) loc@(Location x y) current grid = do
  let grid' = grid & (ix y . ix x) .~ current
  let loc' = moveLocation dir loc
  walk dirs loc' (current + 1) grid'
walk [] _ _ numbers = numbers

moveLocation Down (Location x y) = Location (x) (y + 1)
moveLocation Right (Location x y) = Location (x + 1) (y)
moveLocation Left (Location x y) = Location (x -1) (y)
moveLocation Up (Location x y) = Location (x) (y - 1)
Source Link

Print numbers in a spiral from the center

{- stack
     --install-ghc
     exec ghci
     --package lens
-}

module Main where

import Control.Lens
import Data.List.Lens
import Debug.Trace
import Text.Printf
import Prelude hiding (Left, Right)

data Direction = Up | Left | Down | Right

data Location = Location Int Int

type Grid = [[Int]]

main = printClockwise 25

printClockwise :: Int -> IO ()
printClockwise n = putStrLn $ concatMap printRow grid
  where
    grid = walk directions center 1 emptyGrid
    emptyGrid = replicate sq (take sq (repeat 0))
    printRow row = concatMap (printf "%4s" . show) row ++ "\n"
    -- Ex. for a 5x5 spiral the start location is (2,2)
    center = Location half half
    half = floor $ (fromIntegral sq) / 2
    -- This will return all directions we should walk through the spiral in.
    -- Something like [Right, Down, Left, Left, Up, Up, Right, Right, Right]
    directions = concatMap (\(direction, steps) -> take steps $ repeat direction) (zip directionOrder steps)
    directionOrder = cycle [Right, Down, Left, Up]
    -- Ex. for a spiral up to 25, the steps are 1, 1, 2, 2, 3, 3, 4, 4, 5
    steps = concatMap (take 2 . repeat) [1 .. sq - 1] <> [sq]
    -- Assume the input is a perfect square of an odd number
    sq = ceiling $ sqrt (fromIntegral n)

walk :: [Direction] -> Location -> Int -> Grid -> Grid
walk (dir : dirs) loc@(Location x y) current grid = do
  let grid' = grid & (ix y . ix x) .~ current
  let loc' = moveLocation dir loc
  walk dirs loc' (current + 1) grid'
walk [] _ _ numbers = numbers

moveLocation Down (Location x y) = Location (x) (y + 1)
moveLocation Right (Location x y) = Location (x + 1) (y)
moveLocation Left (Location x y) = Location (x -1) (y)
moveLocation Up (Location x y) = Location (x) (y - 1)

I came across this problem on reddit and thought it'd be fun to try my hand at it in Haskell. The idea is to generate the grid before printing, and the insight to generate that grid was that the movement follows a predictable pattern, of right, down, left, up, and the # of steps taken in a given direction is 1, 1, 2, 2, 3, 3, 4, 4... , n - 1, n -1, n , where n is the square of the input number. So with that you can walk through the grid and fill in the numbers.

The function has no input checking, it assumes the input is a perfect square (of an odd number).