array-forth-0.2.1.4: src/Language/ArrayForth/Core.hs
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE MonadComprehensions #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE StandaloneDeriving #-}
{-# LANGUAGE TypeOperators #-}
-- | This module defines a type representing the location of a core in
-- the 8 × 18 grid.
--
-- All of the actually interesting code is in the typeclass instances.
module Language.ArrayForth.Core where
import Data.Modular
import Text.Printf (printf)
-- | The address of a core. There are 144 cores in an 8 × 18
-- array. The address has the row number followed by the column
-- number.
--
-- As a string, the core addresses are displayed as a single
-- three-digit number, just like in the GreenArray documentation. So
-- @Core 7 17@ becomes @\"717\"@.
--
-- Core addresses behave like numbers: you can use numeric literals
-- and add them together. For example, @[0..] :: [Core]@ gets you the
-- list of all the core addresses. @(move core = core + Core 1 1)@ is
-- a function that moves you up and over by one core.
data Core = Core !(ℤ/8) !(ℤ/18)
-- | Returns all the neighbors of a core. Most cores have four
-- neighbors; the ones along the edges only have three and the ones at
-- the corners two.
--
-- They always come in the order right, down, left up, with Nothing in
-- place of non-existant cores.
neighbors :: Core -> [Maybe Core]
neighbors core@(Core row col) = [ [ core + Core 1 0 | row /= maxBound ]
, [ core + Core 0 1 | col /= maxBound ]
, [ core + Core (-1) 0 | row /= minBound ]
, [ core + Core 0 (- 1) | col /= minBound ] ]
-- Follows the same format as the documentation does: (7, 17) becomes 717.
instance Show Core where show (Core row col) = printf "%d%.2d" (unMod row) (unMod col)
deriving instance Eq Core
deriving instance Ord Core
instance Enum Core where
fromEnum (Core r c) = fromInteger $ unMod r * 18 + unMod c
toEnum n
| n >= 0 && n < 144 = Core (toMod' $ n `div` 18) (toMod' $ n `mod` 18)
| otherwise = error "Core index out of bounds."
-- Taken directly from the documentation for Enum:
enumFrom x = enumFromTo x maxBound
enumFromThen x y = enumFromThenTo x y bound
where bound | fromEnum y >= fromEnum x = maxBound
| otherwise = minBound
instance Bounded Core where
minBound = Core 0 0
maxBound = Core 7 17
-- Core addresses from a group, eh?
instance Num Core where
fromInteger = toEnum . fromIntegral
Core r₁ c₁ + Core r₂ c₂ = Core (r₁ + r₂) (c₁ + c₂)
Core r₁ c₁ * Core r₂ c₂ = Core (r₁ * r₂) (c₁ * c₂)
signum (Core r c) = Core (signum r) (signum c)
abs (Core r c) = Core (abs r) (abs c)
negate (Core r c) = Core (negate r) (negate c)