{-# LANGUAGE TemplateHaskell #-}

-- |
-- SPDX-License-Identifier: BSD-3-Clause
--
-- Structure recognizer types.
--
-- See overview of the structure recognizer feature in
-- "Swarm.Game.Scenario.Topography.Structure.Recognition.Precompute".
--
-- The following structure template shall be used to illustrate
-- roles of the types in this module:
--
-- @
-- cdc
-- aab
-- cdc
-- @
module Swarm.Game.Scenario.Topography.Structure.Recognition.Type where

import Control.Arrow ((&&&))
import Control.Lens (Lens', makeLenses)
import Data.Aeson (ToJSON)
import Data.Function (on)
import Data.HashMap.Strict (HashMap)
import Data.Int (Int32)
import Data.IntSet.NonEmpty (NEIntSet)
import Data.List.NonEmpty (NonEmpty)
import Data.List.NonEmpty qualified as NE
import Data.Map (Map)
import Data.Maybe (catMaybes)
import Data.Ord (Down (Down))
import Data.Semigroup (Max, Min)
import GHC.Generics (Generic)
import Swarm.Game.Location (Location, asVector)
import Swarm.Game.Scenario.Topography.Area
import Swarm.Game.Scenario.Topography.Grid
import Swarm.Game.Scenario.Topography.Structure.Named (NamedArea, StructureName, name)
import Swarm.Game.Scenario.Topography.Structure.Recognition.Static
import Swarm.Game.Universe (Cosmic, SubworldName, offsetBy)
import Swarm.Game.World.Coords (coordsToLoc)
import Swarm.Language.Syntax.Direction (AbsoluteDir)
import Swarm.Util.Lens (makeLensesNoSigs)
import Text.AhoCorasick (StateMachine)

-- | A "needle" consisting of a single cell within
-- the haystack (a row of cells) to be searched.
--
-- === Example
-- A single entity @a@ in the row:
--
-- @
-- aab
-- @
type AtomicKeySymbol a = Maybe a

-- | A "needle" consisting row of cells within the haystack
-- (a sequence of rows) to be searched.
--
-- === Example
-- The complete row:
--
-- @
-- aab
-- @
type SymbolSequence a = [AtomicKeySymbol a]

-- |
-- Position specific to a single entity within a horizontal row.
--
-- === Example
-- For entity @b@ within the row:
--
-- @
-- aab
-- @
--
-- Its '_position' is @2@.
data PositionWithinRow b a = PositionWithinRow
  { forall b a. PositionWithinRow b a -> Int32
_position :: Int32
  -- ^ horizontal index of the entity within the row
  , forall b a. PositionWithinRow b a -> ConsolidatedRowReferences b a
structureRow :: ConsolidatedRowReferences b a
  }

-- | A chunkified version of a structure row.
-- Each unique structure row will need to test one of these
-- against the world row being examined.
data RowChunkMatchingReference b a = RowChunkMatchingReference
  { forall b a.
RowChunkMatchingReference b a -> ConsolidatedRowReferences b a
locatableRows :: ConsolidatedRowReferences b a
  , forall b a.
RowChunkMatchingReference b a
-> HashMap (NonEmpty a) (NonEmpty Int)
confirmationMap :: HashMap (NonEmpty a) (NonEmpty Int)
  }

data PiecewiseRecognition b a = PiecewiseRecognition
  { forall b a.
PiecewiseRecognition b a
-> StateMachine (AtomicKeySymbol a) (NonEmpty a)
piecewiseSM :: StateMachine (AtomicKeySymbol a) (NonEmpty a)
  , forall b a.
PiecewiseRecognition b a
-> NonEmpty (RowChunkMatchingReference b a)
picewiseLookup :: NonEmpty (RowChunkMatchingReference b a)
  -- ^ A lookup structure for use with results of the
  -- Aho-Corasick matcher. This lookup will determine whether
  -- the discontiguous "chunks" found by the matcher occur at
  -- the right positions with respect to the reference structure.
  }

data PositionedChunk a = PositionedChunk
  { forall a. PositionedChunk a -> Int
chunkStartPos :: Int
  , forall a. PositionedChunk a -> NonEmpty a
chunkContents :: NonEmpty a
  }

-- Represents all of the locations that particular entity
-- occurs within a specific row of a particular structure.
--
-- === Example
-- For entity @a@ within the row:
--
-- @
-- aab
-- @
--
-- this record will contain two entries in its 'entityOccurrences' field.
data SingleRowEntityOccurrences b a = SingleRowEntityOccurrences
  { forall b a.
SingleRowEntityOccurrences b a -> ConsolidatedRowReferences b a
myRow :: ConsolidatedRowReferences b a
  , forall b a. SingleRowEntityOccurrences b a -> a
myEntity :: a
  , forall b a. SingleRowEntityOccurrences b a -> [PositionedChunk a]
contiguousChunks :: [PositionedChunk a]
  , forall b a. SingleRowEntityOccurrences b a -> InspectionOffsets
expandedOffsets :: InspectionOffsets
  }

newtype RowWidth = RowWidth Int32
  deriving (RowWidth -> RowWidth -> Bool
(RowWidth -> RowWidth -> Bool)
-> (RowWidth -> RowWidth -> Bool) -> Eq RowWidth
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: RowWidth -> RowWidth -> Bool
== :: RowWidth -> RowWidth -> Bool
$c/= :: RowWidth -> RowWidth -> Bool
/= :: RowWidth -> RowWidth -> Bool
Eq)

-- | A a specific row within a particular structure.
--
-- === Example
-- For the second occurrence of @cdc@ within the structure:
--
-- @
-- cdc
-- aab
-- cdc
-- @
--
-- it's 'rowIndex' is @2@.
--
-- The two type parameters, `b` and `a`, correspond
-- to 'Cell' and 'Entity', respectively.
data StructureRow b a = StructureRow
  { forall b a. StructureRow b a -> StructureWithGrid b a
wholeStructure :: StructureWithGrid b a
  , forall b a. StructureRow b a -> Int32
rowIndex :: Int32
  -- ^ vertical index of the row within the structure
  , forall b a. StructureRow b a -> NonEmpty (AtomicKeySymbol a)
rowContent :: NonEmpty (AtomicKeySymbol a)
  }

-- | Represents all rows across all structures that share
-- a particular row content
data ConsolidatedRowReferences b a = ConsolidatedRowReferences
  { forall b a.
ConsolidatedRowReferences b a -> NonEmpty (AtomicKeySymbol a)
sharedRowContent :: NonEmpty (AtomicKeySymbol a)
  , forall b a.
ConsolidatedRowReferences b a -> NonEmpty (StructureRow b a)
referencingRows :: NonEmpty (StructureRow b a)
  , forall b a. ConsolidatedRowReferences b a -> RowWidth
theRowWidth :: RowWidth
  }

data ExtractedArea b a = ExtractedArea
  { forall b a. ExtractedArea b a -> NamedArea b
originalItem :: NamedArea b
  , forall b a. ExtractedArea b a -> NonEmptyGrid (AtomicKeySymbol a)
extractedGrid :: NonEmptyGrid (AtomicKeySymbol a)
  }
  deriving (Int -> ExtractedArea b a -> ShowS
[ExtractedArea b a] -> ShowS
ExtractedArea b a -> String
(Int -> ExtractedArea b a -> ShowS)
-> (ExtractedArea b a -> String)
-> ([ExtractedArea b a] -> ShowS)
-> Show (ExtractedArea b a)
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
forall b a. (Show b, Show a) => Int -> ExtractedArea b a -> ShowS
forall b a. (Show b, Show a) => [ExtractedArea b a] -> ShowS
forall b a. (Show b, Show a) => ExtractedArea b a -> String
$cshowsPrec :: forall b a. (Show b, Show a) => Int -> ExtractedArea b a -> ShowS
showsPrec :: Int -> ExtractedArea b a -> ShowS
$cshow :: forall b a. (Show b, Show a) => ExtractedArea b a -> String
show :: ExtractedArea b a -> String
$cshowList :: forall b a. (Show b, Show a) => [ExtractedArea b a] -> ShowS
showList :: [ExtractedArea b a] -> ShowS
Show, ExtractedArea b a -> ExtractedArea b a -> Bool
(ExtractedArea b a -> ExtractedArea b a -> Bool)
-> (ExtractedArea b a -> ExtractedArea b a -> Bool)
-> Eq (ExtractedArea b a)
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
forall b a.
(Eq b, Eq a) =>
ExtractedArea b a -> ExtractedArea b a -> Bool
$c== :: forall b a.
(Eq b, Eq a) =>
ExtractedArea b a -> ExtractedArea b a -> Bool
== :: ExtractedArea b a -> ExtractedArea b a -> Bool
$c/= :: forall b a.
(Eq b, Eq a) =>
ExtractedArea b a -> ExtractedArea b a -> Bool
/= :: ExtractedArea b a -> ExtractedArea b a -> Bool
Eq)

-- | The original definition of a structure, bundled
-- with its grid of cells having been extracted for convenience.
--
-- The two type parameters, `b` and `a`, correspond
-- to 'Cell' and 'Entity', respectively.
data StructureWithGrid b a = StructureWithGrid
  { forall b a. StructureWithGrid b a -> AbsoluteDir
rotatedTo :: AbsoluteDir
  , forall b a. StructureWithGrid b a -> RowWidth
gridWidth :: RowWidth
  , forall b a. StructureWithGrid b a -> ExtractedArea b a
entityGrid :: ExtractedArea b a
  }
  deriving (StructureWithGrid b a -> StructureWithGrid b a -> Bool
(StructureWithGrid b a -> StructureWithGrid b a -> Bool)
-> (StructureWithGrid b a -> StructureWithGrid b a -> Bool)
-> Eq (StructureWithGrid b a)
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
forall b a.
(Eq b, Eq a) =>
StructureWithGrid b a -> StructureWithGrid b a -> Bool
$c== :: forall b a.
(Eq b, Eq a) =>
StructureWithGrid b a -> StructureWithGrid b a -> Bool
== :: StructureWithGrid b a -> StructureWithGrid b a -> Bool
$c/= :: forall b a.
(Eq b, Eq a) =>
StructureWithGrid b a -> StructureWithGrid b a -> Bool
/= :: StructureWithGrid b a -> StructureWithGrid b a -> Bool
Eq)

-- | Structure definitions with precomputed metadata for consumption by the UI
data StructureInfo b a = StructureInfo
  { forall b a.
StructureInfo b a -> SymmetryAnnotatedGrid (ExtractedArea b a)
annotatedGrid :: SymmetryAnnotatedGrid (ExtractedArea b a)
  , forall b a. StructureInfo b a -> NonEmptyGrid (AtomicKeySymbol a)
entityProcessedGrid :: NonEmptyGrid (AtomicKeySymbol a)
  , forall b a. StructureInfo b a -> Map a Int
entityCounts :: Map a Int
  }

-- | For all of the rows that contain a given entity
-- (and are recognized by a single automaton),
-- compute the left-most and right-most position
-- within the row that the given entity may occur.
--
-- This determines how far to the left and to the right
-- our search of the world cells needs to begin and
-- end, respectively.
--
-- The 'Semigroup' instance always grows in extent, taking the minimum
-- of the leftward offsets and the maximum of the rightward offsets.
data InspectionOffsets = InspectionOffsets
  { InspectionOffsets -> Min Int32
startOffset :: Min Int32
  -- ^ Always non-positive (i.e. either zero or negative).
  -- For the first-level search, this extends to the left.
  -- For the second-level search, this extends upward.
  , InspectionOffsets -> Max Int32
endOffset :: Max Int32
  -- ^ Always non-negative.
  -- For the first-level search, this extends to the right.
  -- For the second-level search, this extends downward.
  }
  deriving (Int -> InspectionOffsets -> ShowS
[InspectionOffsets] -> ShowS
InspectionOffsets -> String
(Int -> InspectionOffsets -> ShowS)
-> (InspectionOffsets -> String)
-> ([InspectionOffsets] -> ShowS)
-> Show InspectionOffsets
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> InspectionOffsets -> ShowS
showsPrec :: Int -> InspectionOffsets -> ShowS
$cshow :: InspectionOffsets -> String
show :: InspectionOffsets -> String
$cshowList :: [InspectionOffsets] -> ShowS
showList :: [InspectionOffsets] -> ShowS
Show, (forall x. InspectionOffsets -> Rep InspectionOffsets x)
-> (forall x. Rep InspectionOffsets x -> InspectionOffsets)
-> Generic InspectionOffsets
forall x. Rep InspectionOffsets x -> InspectionOffsets
forall x. InspectionOffsets -> Rep InspectionOffsets x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cfrom :: forall x. InspectionOffsets -> Rep InspectionOffsets x
from :: forall x. InspectionOffsets -> Rep InspectionOffsets x
$cto :: forall x. Rep InspectionOffsets x -> InspectionOffsets
to :: forall x. Rep InspectionOffsets x -> InspectionOffsets
Generic, [InspectionOffsets] -> Value
[InspectionOffsets] -> Encoding
InspectionOffsets -> Bool
InspectionOffsets -> Value
InspectionOffsets -> Encoding
(InspectionOffsets -> Value)
-> (InspectionOffsets -> Encoding)
-> ([InspectionOffsets] -> Value)
-> ([InspectionOffsets] -> Encoding)
-> (InspectionOffsets -> Bool)
-> ToJSON InspectionOffsets
forall a.
(a -> Value)
-> (a -> Encoding)
-> ([a] -> Value)
-> ([a] -> Encoding)
-> (a -> Bool)
-> ToJSON a
$ctoJSON :: InspectionOffsets -> Value
toJSON :: InspectionOffsets -> Value
$ctoEncoding :: InspectionOffsets -> Encoding
toEncoding :: InspectionOffsets -> Encoding
$ctoJSONList :: [InspectionOffsets] -> Value
toJSONList :: [InspectionOffsets] -> Value
$ctoEncodingList :: [InspectionOffsets] -> Encoding
toEncodingList :: [InspectionOffsets] -> Encoding
$comitField :: InspectionOffsets -> Bool
omitField :: InspectionOffsets -> Bool
ToJSON)

instance Semigroup InspectionOffsets where
  InspectionOffsets Min Int32
l1 Max Int32
r1 <> :: InspectionOffsets -> InspectionOffsets -> InspectionOffsets
<> InspectionOffsets Min Int32
l2 Max Int32
r2 =
    Min Int32 -> Max Int32 -> InspectionOffsets
InspectionOffsets (Min Int32
l1 Min Int32 -> Min Int32 -> Min Int32
forall a. Semigroup a => a -> a -> a
<> Min Int32
l2) (Max Int32
r1 Max Int32 -> Max Int32 -> Max Int32
forall a. Semigroup a => a -> a -> a
<> Max Int32
r2)

data AutomatonInfo v k = AutomatonInfo
  { forall v k. AutomatonInfo v k -> InspectionOffsets
_inspectionOffsets :: InspectionOffsets
  , forall v k. AutomatonInfo v k -> PiecewiseRecognition v k
_piecewiseRecognizer :: PiecewiseRecognition v k
  }
  deriving ((forall x. AutomatonInfo v k -> Rep (AutomatonInfo v k) x)
-> (forall x. Rep (AutomatonInfo v k) x -> AutomatonInfo v k)
-> Generic (AutomatonInfo v k)
forall x. Rep (AutomatonInfo v k) x -> AutomatonInfo v k
forall x. AutomatonInfo v k -> Rep (AutomatonInfo v k) x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
forall v k x. Rep (AutomatonInfo v k) x -> AutomatonInfo v k
forall v k x. AutomatonInfo v k -> Rep (AutomatonInfo v k) x
$cfrom :: forall v k x. AutomatonInfo v k -> Rep (AutomatonInfo v k) x
from :: forall x. AutomatonInfo v k -> Rep (AutomatonInfo v k) x
$cto :: forall v k x. Rep (AutomatonInfo v k) x -> AutomatonInfo v k
to :: forall x. Rep (AutomatonInfo v k) x -> AutomatonInfo v k
Generic)

makeLenses ''AutomatonInfo

-- | The complete set of data needed to identify applicable
-- structures, based on a just-placed entity.
data RecognizerAutomatons b a = RecognizerAutomatons
  { forall b a.
RecognizerAutomatons b a -> Map StructureName (StructureInfo b a)
_originalStructureDefinitions :: Map StructureName (StructureInfo b a)
  -- ^ all of the structures that shall participate in automatic recognition.
  -- This list is used only by the UI and by the 'Floorplan' command.
  , forall b a.
RecognizerAutomatons b a -> HashMap a (AutomatonInfo b a)
_automatonsByEntity :: HashMap a (AutomatonInfo b a)
  }
  deriving ((forall x.
 RecognizerAutomatons b a -> Rep (RecognizerAutomatons b a) x)
-> (forall x.
    Rep (RecognizerAutomatons b a) x -> RecognizerAutomatons b a)
-> Generic (RecognizerAutomatons b a)
forall x.
Rep (RecognizerAutomatons b a) x -> RecognizerAutomatons b a
forall x.
RecognizerAutomatons b a -> Rep (RecognizerAutomatons b a) x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
forall b a x.
Rep (RecognizerAutomatons b a) x -> RecognizerAutomatons b a
forall b a x.
RecognizerAutomatons b a -> Rep (RecognizerAutomatons b a) x
$cfrom :: forall b a x.
RecognizerAutomatons b a -> Rep (RecognizerAutomatons b a) x
from :: forall x.
RecognizerAutomatons b a -> Rep (RecognizerAutomatons b a) x
$cto :: forall b a x.
Rep (RecognizerAutomatons b a) x -> RecognizerAutomatons b a
to :: forall x.
Rep (RecognizerAutomatons b a) x -> RecognizerAutomatons b a
Generic)

makeLenses ''RecognizerAutomatons

-- | Final output of the search process.
-- These are the elements that are stored in the 'FoundRegistry'.
--
-- The two type parameters, `b` and `a`, correspond
-- to 'Cell' and 'Entity', respectively.
type FoundStructure b a = PositionedStructure (StructureWithGrid b a)

-- | NOTE: A structure's name + orientation + position will uniquely
-- identify it in the world.  Note that position alone is not sufficient;
-- due to transparency, a completely intact smaller structure can co-exist
-- within a larger structure, both sharing the same upper-left coordinate.
-- However, two identical structures (with identical orientation) cannot
-- occupy the same space.
--
-- Compare "PositionedStructure OrientedStructure" to:
-- "Swarm.Game.Scenario.Topography.Structure.Recognition.Static.LocatedStructure"
data PositionedStructure s = PositionedStructure
  { forall s. PositionedStructure s -> Cosmic Location
upperLeftCorner :: Cosmic Location
  , forall s. PositionedStructure s -> s
structureWithGrid :: s
  }
  deriving (PositionedStructure s -> PositionedStructure s -> Bool
(PositionedStructure s -> PositionedStructure s -> Bool)
-> (PositionedStructure s -> PositionedStructure s -> Bool)
-> Eq (PositionedStructure s)
forall s.
Eq s =>
PositionedStructure s -> PositionedStructure s -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: forall s.
Eq s =>
PositionedStructure s -> PositionedStructure s -> Bool
== :: PositionedStructure s -> PositionedStructure s -> Bool
$c/= :: forall s.
Eq s =>
PositionedStructure s -> PositionedStructure s -> Bool
/= :: PositionedStructure s -> PositionedStructure s -> Bool
Eq, (forall a b.
 (a -> b) -> PositionedStructure a -> PositionedStructure b)
-> (forall a b.
    a -> PositionedStructure b -> PositionedStructure a)
-> Functor PositionedStructure
forall a b. a -> PositionedStructure b -> PositionedStructure a
forall a b.
(a -> b) -> PositionedStructure a -> PositionedStructure b
forall (f :: * -> *).
(forall a b. (a -> b) -> f a -> f b)
-> (forall a b. a -> f b -> f a) -> Functor f
$cfmap :: forall a b.
(a -> b) -> PositionedStructure a -> PositionedStructure b
fmap :: forall a b.
(a -> b) -> PositionedStructure a -> PositionedStructure b
$c<$ :: forall a b. a -> PositionedStructure b -> PositionedStructure a
<$ :: forall a b. a -> PositionedStructure b -> PositionedStructure a
Functor, (forall x. PositionedStructure s -> Rep (PositionedStructure s) x)
-> (forall x.
    Rep (PositionedStructure s) x -> PositionedStructure s)
-> Generic (PositionedStructure s)
forall x. Rep (PositionedStructure s) x -> PositionedStructure s
forall x. PositionedStructure s -> Rep (PositionedStructure s) x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
forall s x. Rep (PositionedStructure s) x -> PositionedStructure s
forall s x. PositionedStructure s -> Rep (PositionedStructure s) x
$cfrom :: forall s x. PositionedStructure s -> Rep (PositionedStructure s) x
from :: forall x. PositionedStructure s -> Rep (PositionedStructure s) x
$cto :: forall s x. Rep (PositionedStructure s) x -> PositionedStructure s
to :: forall x. Rep (PositionedStructure s) x -> PositionedStructure s
Generic, [PositionedStructure s] -> Value
[PositionedStructure s] -> Encoding
PositionedStructure s -> Bool
PositionedStructure s -> Value
PositionedStructure s -> Encoding
(PositionedStructure s -> Value)
-> (PositionedStructure s -> Encoding)
-> ([PositionedStructure s] -> Value)
-> ([PositionedStructure s] -> Encoding)
-> (PositionedStructure s -> Bool)
-> ToJSON (PositionedStructure s)
forall s. ToJSON s => [PositionedStructure s] -> Value
forall s. ToJSON s => [PositionedStructure s] -> Encoding
forall s. ToJSON s => PositionedStructure s -> Bool
forall s. ToJSON s => PositionedStructure s -> Value
forall s. ToJSON s => PositionedStructure s -> Encoding
forall a.
(a -> Value)
-> (a -> Encoding)
-> ([a] -> Value)
-> ([a] -> Encoding)
-> (a -> Bool)
-> ToJSON a
$ctoJSON :: forall s. ToJSON s => PositionedStructure s -> Value
toJSON :: PositionedStructure s -> Value
$ctoEncoding :: forall s. ToJSON s => PositionedStructure s -> Encoding
toEncoding :: PositionedStructure s -> Encoding
$ctoJSONList :: forall s. ToJSON s => [PositionedStructure s] -> Value
toJSONList :: [PositionedStructure s] -> Value
$ctoEncodingList :: forall s. ToJSON s => [PositionedStructure s] -> Encoding
toEncodingList :: [PositionedStructure s] -> Encoding
$comitField :: forall s. ToJSON s => PositionedStructure s -> Bool
omitField :: PositionedStructure s -> Bool
ToJSON)

deriving instance (Ord (PositionedStructure OrientedStructure))

data FoundRowFromChunk a = FoundRowFromChunk
  { forall a. FoundRowFromChunk a -> Int
chunkOffsetFromSearchBorder :: Int
  , forall a. FoundRowFromChunk a -> Int32
horizontalStructPos :: Int32
  , forall a. FoundRowFromChunk a -> a
chunkStructure :: a
  }
  deriving ((forall a b.
 (a -> b) -> FoundRowFromChunk a -> FoundRowFromChunk b)
-> (forall a b. a -> FoundRowFromChunk b -> FoundRowFromChunk a)
-> Functor FoundRowFromChunk
forall a b. a -> FoundRowFromChunk b -> FoundRowFromChunk a
forall a b. (a -> b) -> FoundRowFromChunk a -> FoundRowFromChunk b
forall (f :: * -> *).
(forall a b. (a -> b) -> f a -> f b)
-> (forall a b. a -> f b -> f a) -> Functor f
$cfmap :: forall a b. (a -> b) -> FoundRowFromChunk a -> FoundRowFromChunk b
fmap :: forall a b. (a -> b) -> FoundRowFromChunk a -> FoundRowFromChunk b
$c<$ :: forall a b. a -> FoundRowFromChunk b -> FoundRowFromChunk a
<$ :: forall a b. a -> FoundRowFromChunk b -> FoundRowFromChunk a
Functor, (forall x. FoundRowFromChunk a -> Rep (FoundRowFromChunk a) x)
-> (forall x. Rep (FoundRowFromChunk a) x -> FoundRowFromChunk a)
-> Generic (FoundRowFromChunk a)
forall x. Rep (FoundRowFromChunk a) x -> FoundRowFromChunk a
forall x. FoundRowFromChunk a -> Rep (FoundRowFromChunk a) x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
forall a x. Rep (FoundRowFromChunk a) x -> FoundRowFromChunk a
forall a x. FoundRowFromChunk a -> Rep (FoundRowFromChunk a) x
$cfrom :: forall a x. FoundRowFromChunk a -> Rep (FoundRowFromChunk a) x
from :: forall x. FoundRowFromChunk a -> Rep (FoundRowFromChunk a) x
$cto :: forall a x. Rep (FoundRowFromChunk a) x -> FoundRowFromChunk a
to :: forall x. Rep (FoundRowFromChunk a) x -> FoundRowFromChunk a
Generic, [FoundRowFromChunk a] -> Value
[FoundRowFromChunk a] -> Encoding
FoundRowFromChunk a -> Bool
FoundRowFromChunk a -> Value
FoundRowFromChunk a -> Encoding
(FoundRowFromChunk a -> Value)
-> (FoundRowFromChunk a -> Encoding)
-> ([FoundRowFromChunk a] -> Value)
-> ([FoundRowFromChunk a] -> Encoding)
-> (FoundRowFromChunk a -> Bool)
-> ToJSON (FoundRowFromChunk a)
forall a. ToJSON a => [FoundRowFromChunk a] -> Value
forall a. ToJSON a => [FoundRowFromChunk a] -> Encoding
forall a. ToJSON a => FoundRowFromChunk a -> Bool
forall a. ToJSON a => FoundRowFromChunk a -> Value
forall a. ToJSON a => FoundRowFromChunk a -> Encoding
forall a.
(a -> Value)
-> (a -> Encoding)
-> ([a] -> Value)
-> ([a] -> Encoding)
-> (a -> Bool)
-> ToJSON a
$ctoJSON :: forall a. ToJSON a => FoundRowFromChunk a -> Value
toJSON :: FoundRowFromChunk a -> Value
$ctoEncoding :: forall a. ToJSON a => FoundRowFromChunk a -> Encoding
toEncoding :: FoundRowFromChunk a -> Encoding
$ctoJSONList :: forall a. ToJSON a => [FoundRowFromChunk a] -> Value
toJSONList :: [FoundRowFromChunk a] -> Value
$ctoEncodingList :: forall a. ToJSON a => [FoundRowFromChunk a] -> Encoding
toEncodingList :: [FoundRowFromChunk a] -> Encoding
$comitField :: forall a. ToJSON a => FoundRowFromChunk a -> Bool
omitField :: FoundRowFromChunk a -> Bool
ToJSON)

-- | The located occurrences of a specific contiguous chunk of entities.
-- Note that an identical chunk may recur more than once in a structure row.
-- This record represents all of the recurrences of one such chunk.
--
-- Any different chunks contained within a row will be described by
-- their own instance of this record.
data FoundAndExpectedChunkPositions = FoundAndExpectedChunkPositions
  { FoundAndExpectedChunkPositions -> NEIntSet
foundPositions :: NEIntSet
  , FoundAndExpectedChunkPositions -> NEIntSet
expectedPositions :: NEIntSet
  }
  deriving ((forall x.
 FoundAndExpectedChunkPositions
 -> Rep FoundAndExpectedChunkPositions x)
-> (forall x.
    Rep FoundAndExpectedChunkPositions x
    -> FoundAndExpectedChunkPositions)
-> Generic FoundAndExpectedChunkPositions
forall x.
Rep FoundAndExpectedChunkPositions x
-> FoundAndExpectedChunkPositions
forall x.
FoundAndExpectedChunkPositions
-> Rep FoundAndExpectedChunkPositions x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cfrom :: forall x.
FoundAndExpectedChunkPositions
-> Rep FoundAndExpectedChunkPositions x
from :: forall x.
FoundAndExpectedChunkPositions
-> Rep FoundAndExpectedChunkPositions x
$cto :: forall x.
Rep FoundAndExpectedChunkPositions x
-> FoundAndExpectedChunkPositions
to :: forall x.
Rep FoundAndExpectedChunkPositions x
-> FoundAndExpectedChunkPositions
Generic, [FoundAndExpectedChunkPositions] -> Value
[FoundAndExpectedChunkPositions] -> Encoding
FoundAndExpectedChunkPositions -> Bool
FoundAndExpectedChunkPositions -> Value
FoundAndExpectedChunkPositions -> Encoding
(FoundAndExpectedChunkPositions -> Value)
-> (FoundAndExpectedChunkPositions -> Encoding)
-> ([FoundAndExpectedChunkPositions] -> Value)
-> ([FoundAndExpectedChunkPositions] -> Encoding)
-> (FoundAndExpectedChunkPositions -> Bool)
-> ToJSON FoundAndExpectedChunkPositions
forall a.
(a -> Value)
-> (a -> Encoding)
-> ([a] -> Value)
-> ([a] -> Encoding)
-> (a -> Bool)
-> ToJSON a
$ctoJSON :: FoundAndExpectedChunkPositions -> Value
toJSON :: FoundAndExpectedChunkPositions -> Value
$ctoEncoding :: FoundAndExpectedChunkPositions -> Encoding
toEncoding :: FoundAndExpectedChunkPositions -> Encoding
$ctoJSONList :: [FoundAndExpectedChunkPositions] -> Value
toJSONList :: [FoundAndExpectedChunkPositions] -> Value
$ctoEncodingList :: [FoundAndExpectedChunkPositions] -> Encoding
toEncodingList :: [FoundAndExpectedChunkPositions] -> Encoding
$comitField :: FoundAndExpectedChunkPositions -> Bool
omitField :: FoundAndExpectedChunkPositions -> Bool
ToJSON)

data ChunkedRowMatch a e = ChunkedRowMatch
  { forall a e.
ChunkedRowMatch a e
-> [(FoundAndExpectedChunkPositions, NonEmpty e)]
positionsComparison :: [(FoundAndExpectedChunkPositions, NonEmpty e)]
  , forall a e. ChunkedRowMatch a e -> FoundRowFromChunk a
foundChunkRow :: FoundRowFromChunk a
  }
  deriving ((forall a b.
 (a -> b) -> ChunkedRowMatch a a -> ChunkedRowMatch a b)
-> (forall a b. a -> ChunkedRowMatch a b -> ChunkedRowMatch a a)
-> Functor (ChunkedRowMatch a)
forall a b. a -> ChunkedRowMatch a b -> ChunkedRowMatch a a
forall a b. (a -> b) -> ChunkedRowMatch a a -> ChunkedRowMatch a b
forall a a b. a -> ChunkedRowMatch a b -> ChunkedRowMatch a a
forall a a b.
(a -> b) -> ChunkedRowMatch a a -> ChunkedRowMatch a b
forall (f :: * -> *).
(forall a b. (a -> b) -> f a -> f b)
-> (forall a b. a -> f b -> f a) -> Functor f
$cfmap :: forall a a b.
(a -> b) -> ChunkedRowMatch a a -> ChunkedRowMatch a b
fmap :: forall a b. (a -> b) -> ChunkedRowMatch a a -> ChunkedRowMatch a b
$c<$ :: forall a a b. a -> ChunkedRowMatch a b -> ChunkedRowMatch a a
<$ :: forall a b. a -> ChunkedRowMatch a b -> ChunkedRowMatch a a
Functor, (forall x. ChunkedRowMatch a e -> Rep (ChunkedRowMatch a e) x)
-> (forall x. Rep (ChunkedRowMatch a e) x -> ChunkedRowMatch a e)
-> Generic (ChunkedRowMatch a e)
forall x. Rep (ChunkedRowMatch a e) x -> ChunkedRowMatch a e
forall x. ChunkedRowMatch a e -> Rep (ChunkedRowMatch a e) x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
forall a e x. Rep (ChunkedRowMatch a e) x -> ChunkedRowMatch a e
forall a e x. ChunkedRowMatch a e -> Rep (ChunkedRowMatch a e) x
$cfrom :: forall a e x. ChunkedRowMatch a e -> Rep (ChunkedRowMatch a e) x
from :: forall x. ChunkedRowMatch a e -> Rep (ChunkedRowMatch a e) x
$cto :: forall a e x. Rep (ChunkedRowMatch a e) x -> ChunkedRowMatch a e
to :: forall x. Rep (ChunkedRowMatch a e) x -> ChunkedRowMatch a e
Generic, [ChunkedRowMatch a e] -> Value
[ChunkedRowMatch a e] -> Encoding
ChunkedRowMatch a e -> Bool
ChunkedRowMatch a e -> Value
ChunkedRowMatch a e -> Encoding
(ChunkedRowMatch a e -> Value)
-> (ChunkedRowMatch a e -> Encoding)
-> ([ChunkedRowMatch a e] -> Value)
-> ([ChunkedRowMatch a e] -> Encoding)
-> (ChunkedRowMatch a e -> Bool)
-> ToJSON (ChunkedRowMatch a e)
forall a.
(a -> Value)
-> (a -> Encoding)
-> ([a] -> Value)
-> ([a] -> Encoding)
-> (a -> Bool)
-> ToJSON a
forall a e. (ToJSON a, ToJSON e) => [ChunkedRowMatch a e] -> Value
forall a e.
(ToJSON a, ToJSON e) =>
[ChunkedRowMatch a e] -> Encoding
forall a e. (ToJSON a, ToJSON e) => ChunkedRowMatch a e -> Bool
forall a e. (ToJSON a, ToJSON e) => ChunkedRowMatch a e -> Value
forall a e. (ToJSON a, ToJSON e) => ChunkedRowMatch a e -> Encoding
$ctoJSON :: forall a e. (ToJSON a, ToJSON e) => ChunkedRowMatch a e -> Value
toJSON :: ChunkedRowMatch a e -> Value
$ctoEncoding :: forall a e. (ToJSON a, ToJSON e) => ChunkedRowMatch a e -> Encoding
toEncoding :: ChunkedRowMatch a e -> Encoding
$ctoJSONList :: forall a e. (ToJSON a, ToJSON e) => [ChunkedRowMatch a e] -> Value
toJSONList :: [ChunkedRowMatch a e] -> Value
$ctoEncodingList :: forall a e.
(ToJSON a, ToJSON e) =>
[ChunkedRowMatch a e] -> Encoding
toEncodingList :: [ChunkedRowMatch a e] -> Encoding
$comitField :: forall a e. (ToJSON a, ToJSON e) => ChunkedRowMatch a e -> Bool
omitField :: ChunkedRowMatch a e -> Bool
ToJSON)

data EntityDiscrepancy e = EntityDiscrepancy
  { forall e. EntityDiscrepancy e -> e
expectedEntity :: e
  , forall e. EntityDiscrepancy e -> AtomicKeySymbol e
observedEntity :: AtomicKeySymbol e
  }
  deriving ((forall a b.
 (a -> b) -> EntityDiscrepancy a -> EntityDiscrepancy b)
-> (forall a b. a -> EntityDiscrepancy b -> EntityDiscrepancy a)
-> Functor EntityDiscrepancy
forall a b. a -> EntityDiscrepancy b -> EntityDiscrepancy a
forall a b. (a -> b) -> EntityDiscrepancy a -> EntityDiscrepancy b
forall (f :: * -> *).
(forall a b. (a -> b) -> f a -> f b)
-> (forall a b. a -> f b -> f a) -> Functor f
$cfmap :: forall a b. (a -> b) -> EntityDiscrepancy a -> EntityDiscrepancy b
fmap :: forall a b. (a -> b) -> EntityDiscrepancy a -> EntityDiscrepancy b
$c<$ :: forall a b. a -> EntityDiscrepancy b -> EntityDiscrepancy a
<$ :: forall a b. a -> EntityDiscrepancy b -> EntityDiscrepancy a
Functor, (forall x. EntityDiscrepancy e -> Rep (EntityDiscrepancy e) x)
-> (forall x. Rep (EntityDiscrepancy e) x -> EntityDiscrepancy e)
-> Generic (EntityDiscrepancy e)
forall x. Rep (EntityDiscrepancy e) x -> EntityDiscrepancy e
forall x. EntityDiscrepancy e -> Rep (EntityDiscrepancy e) x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
forall e x. Rep (EntityDiscrepancy e) x -> EntityDiscrepancy e
forall e x. EntityDiscrepancy e -> Rep (EntityDiscrepancy e) x
$cfrom :: forall e x. EntityDiscrepancy e -> Rep (EntityDiscrepancy e) x
from :: forall x. EntityDiscrepancy e -> Rep (EntityDiscrepancy e) x
$cto :: forall e x. Rep (EntityDiscrepancy e) x -> EntityDiscrepancy e
to :: forall x. Rep (EntityDiscrepancy e) x -> EntityDiscrepancy e
Generic, [EntityDiscrepancy e] -> Value
[EntityDiscrepancy e] -> Encoding
EntityDiscrepancy e -> Bool
EntityDiscrepancy e -> Value
EntityDiscrepancy e -> Encoding
(EntityDiscrepancy e -> Value)
-> (EntityDiscrepancy e -> Encoding)
-> ([EntityDiscrepancy e] -> Value)
-> ([EntityDiscrepancy e] -> Encoding)
-> (EntityDiscrepancy e -> Bool)
-> ToJSON (EntityDiscrepancy e)
forall e. ToJSON e => [EntityDiscrepancy e] -> Value
forall e. ToJSON e => [EntityDiscrepancy e] -> Encoding
forall e. ToJSON e => EntityDiscrepancy e -> Bool
forall e. ToJSON e => EntityDiscrepancy e -> Value
forall e. ToJSON e => EntityDiscrepancy e -> Encoding
forall a.
(a -> Value)
-> (a -> Encoding)
-> ([a] -> Value)
-> ([a] -> Encoding)
-> (a -> Bool)
-> ToJSON a
$ctoJSON :: forall e. ToJSON e => EntityDiscrepancy e -> Value
toJSON :: EntityDiscrepancy e -> Value
$ctoEncoding :: forall e. ToJSON e => EntityDiscrepancy e -> Encoding
toEncoding :: EntityDiscrepancy e -> Encoding
$ctoJSONList :: forall e. ToJSON e => [EntityDiscrepancy e] -> Value
toJSONList :: [EntityDiscrepancy e] -> Value
$ctoEncodingList :: forall e. ToJSON e => [EntityDiscrepancy e] -> Encoding
toEncodingList :: [EntityDiscrepancy e] -> Encoding
$comitField :: forall e. ToJSON e => EntityDiscrepancy e -> Bool
omitField :: EntityDiscrepancy e -> Bool
ToJSON)

distillLabel :: StructureWithGrid b a -> OrientedStructure
distillLabel :: forall b a. StructureWithGrid b a -> OrientedStructure
distillLabel StructureWithGrid b a
swg = StructureName -> AbsoluteDir -> OrientedStructure
OrientedStructure (NamedArea b -> StructureName
forall a. NamedArea a -> StructureName
name (NamedArea b -> StructureName) -> NamedArea b -> StructureName
forall a b. (a -> b) -> a -> b
$ ExtractedArea b a -> NamedArea b
forall b a. ExtractedArea b a -> NamedArea b
originalItem (ExtractedArea b a -> NamedArea b)
-> ExtractedArea b a -> NamedArea b
forall a b. (a -> b) -> a -> b
$ StructureWithGrid b a -> ExtractedArea b a
forall b a. StructureWithGrid b a -> ExtractedArea b a
entityGrid StructureWithGrid b a
swg) (StructureWithGrid b a -> AbsoluteDir
forall b a. StructureWithGrid b a -> AbsoluteDir
rotatedTo StructureWithGrid b a
swg)

data IntactnessFailureReason e
  = DiscrepantEntity (EntityDiscrepancy e)
  | AlreadyUsedBy OrientedStructure
  deriving ((forall a b.
 (a -> b) -> IntactnessFailureReason a -> IntactnessFailureReason b)
-> (forall a b.
    a -> IntactnessFailureReason b -> IntactnessFailureReason a)
-> Functor IntactnessFailureReason
forall a b.
a -> IntactnessFailureReason b -> IntactnessFailureReason a
forall a b.
(a -> b) -> IntactnessFailureReason a -> IntactnessFailureReason b
forall (f :: * -> *).
(forall a b. (a -> b) -> f a -> f b)
-> (forall a b. a -> f b -> f a) -> Functor f
$cfmap :: forall a b.
(a -> b) -> IntactnessFailureReason a -> IntactnessFailureReason b
fmap :: forall a b.
(a -> b) -> IntactnessFailureReason a -> IntactnessFailureReason b
$c<$ :: forall a b.
a -> IntactnessFailureReason b -> IntactnessFailureReason a
<$ :: forall a b.
a -> IntactnessFailureReason b -> IntactnessFailureReason a
Functor, (forall x.
 IntactnessFailureReason e -> Rep (IntactnessFailureReason e) x)
-> (forall x.
    Rep (IntactnessFailureReason e) x -> IntactnessFailureReason e)
-> Generic (IntactnessFailureReason e)
forall x.
Rep (IntactnessFailureReason e) x -> IntactnessFailureReason e
forall x.
IntactnessFailureReason e -> Rep (IntactnessFailureReason e) x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
forall e x.
Rep (IntactnessFailureReason e) x -> IntactnessFailureReason e
forall e x.
IntactnessFailureReason e -> Rep (IntactnessFailureReason e) x
$cfrom :: forall e x.
IntactnessFailureReason e -> Rep (IntactnessFailureReason e) x
from :: forall x.
IntactnessFailureReason e -> Rep (IntactnessFailureReason e) x
$cto :: forall e x.
Rep (IntactnessFailureReason e) x -> IntactnessFailureReason e
to :: forall x.
Rep (IntactnessFailureReason e) x -> IntactnessFailureReason e
Generic, [IntactnessFailureReason e] -> Value
[IntactnessFailureReason e] -> Encoding
IntactnessFailureReason e -> Bool
IntactnessFailureReason e -> Value
IntactnessFailureReason e -> Encoding
(IntactnessFailureReason e -> Value)
-> (IntactnessFailureReason e -> Encoding)
-> ([IntactnessFailureReason e] -> Value)
-> ([IntactnessFailureReason e] -> Encoding)
-> (IntactnessFailureReason e -> Bool)
-> ToJSON (IntactnessFailureReason e)
forall e. ToJSON e => [IntactnessFailureReason e] -> Value
forall e. ToJSON e => [IntactnessFailureReason e] -> Encoding
forall e. ToJSON e => IntactnessFailureReason e -> Bool
forall e. ToJSON e => IntactnessFailureReason e -> Value
forall e. ToJSON e => IntactnessFailureReason e -> Encoding
forall a.
(a -> Value)
-> (a -> Encoding)
-> ([a] -> Value)
-> ([a] -> Encoding)
-> (a -> Bool)
-> ToJSON a
$ctoJSON :: forall e. ToJSON e => IntactnessFailureReason e -> Value
toJSON :: IntactnessFailureReason e -> Value
$ctoEncoding :: forall e. ToJSON e => IntactnessFailureReason e -> Encoding
toEncoding :: IntactnessFailureReason e -> Encoding
$ctoJSONList :: forall e. ToJSON e => [IntactnessFailureReason e] -> Value
toJSONList :: [IntactnessFailureReason e] -> Value
$ctoEncodingList :: forall e. ToJSON e => [IntactnessFailureReason e] -> Encoding
toEncodingList :: [IntactnessFailureReason e] -> Encoding
$comitField :: forall e. ToJSON e => IntactnessFailureReason e -> Bool
omitField :: IntactnessFailureReason e -> Bool
ToJSON)

data StructureIntactnessFailure e = StructureIntactnessFailure
  { forall e. StructureIntactnessFailure e -> Location
failedOnIndex :: Location
  , forall e. StructureIntactnessFailure e -> AreaDimensions
totalSize :: AreaDimensions
  , forall e. StructureIntactnessFailure e -> IntactnessFailureReason e
reason :: IntactnessFailureReason e
  }
  deriving ((forall a b.
 (a -> b)
 -> StructureIntactnessFailure a -> StructureIntactnessFailure b)
-> (forall a b.
    a -> StructureIntactnessFailure b -> StructureIntactnessFailure a)
-> Functor StructureIntactnessFailure
forall a b.
a -> StructureIntactnessFailure b -> StructureIntactnessFailure a
forall a b.
(a -> b)
-> StructureIntactnessFailure a -> StructureIntactnessFailure b
forall (f :: * -> *).
(forall a b. (a -> b) -> f a -> f b)
-> (forall a b. a -> f b -> f a) -> Functor f
$cfmap :: forall a b.
(a -> b)
-> StructureIntactnessFailure a -> StructureIntactnessFailure b
fmap :: forall a b.
(a -> b)
-> StructureIntactnessFailure a -> StructureIntactnessFailure b
$c<$ :: forall a b.
a -> StructureIntactnessFailure b -> StructureIntactnessFailure a
<$ :: forall a b.
a -> StructureIntactnessFailure b -> StructureIntactnessFailure a
Functor, (forall x.
 StructureIntactnessFailure e
 -> Rep (StructureIntactnessFailure e) x)
-> (forall x.
    Rep (StructureIntactnessFailure e) x
    -> StructureIntactnessFailure e)
-> Generic (StructureIntactnessFailure e)
forall x.
Rep (StructureIntactnessFailure e) x
-> StructureIntactnessFailure e
forall x.
StructureIntactnessFailure e
-> Rep (StructureIntactnessFailure e) x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
forall e x.
Rep (StructureIntactnessFailure e) x
-> StructureIntactnessFailure e
forall e x.
StructureIntactnessFailure e
-> Rep (StructureIntactnessFailure e) x
$cfrom :: forall e x.
StructureIntactnessFailure e
-> Rep (StructureIntactnessFailure e) x
from :: forall x.
StructureIntactnessFailure e
-> Rep (StructureIntactnessFailure e) x
$cto :: forall e x.
Rep (StructureIntactnessFailure e) x
-> StructureIntactnessFailure e
to :: forall x.
Rep (StructureIntactnessFailure e) x
-> StructureIntactnessFailure e
Generic, [StructureIntactnessFailure e] -> Value
[StructureIntactnessFailure e] -> Encoding
StructureIntactnessFailure e -> Bool
StructureIntactnessFailure e -> Value
StructureIntactnessFailure e -> Encoding
(StructureIntactnessFailure e -> Value)
-> (StructureIntactnessFailure e -> Encoding)
-> ([StructureIntactnessFailure e] -> Value)
-> ([StructureIntactnessFailure e] -> Encoding)
-> (StructureIntactnessFailure e -> Bool)
-> ToJSON (StructureIntactnessFailure e)
forall e. ToJSON e => [StructureIntactnessFailure e] -> Value
forall e. ToJSON e => [StructureIntactnessFailure e] -> Encoding
forall e. ToJSON e => StructureIntactnessFailure e -> Bool
forall e. ToJSON e => StructureIntactnessFailure e -> Value
forall e. ToJSON e => StructureIntactnessFailure e -> Encoding
forall a.
(a -> Value)
-> (a -> Encoding)
-> ([a] -> Value)
-> ([a] -> Encoding)
-> (a -> Bool)
-> ToJSON a
$ctoJSON :: forall e. ToJSON e => StructureIntactnessFailure e -> Value
toJSON :: StructureIntactnessFailure e -> Value
$ctoEncoding :: forall e. ToJSON e => StructureIntactnessFailure e -> Encoding
toEncoding :: StructureIntactnessFailure e -> Encoding
$ctoJSONList :: forall e. ToJSON e => [StructureIntactnessFailure e] -> Value
toJSONList :: [StructureIntactnessFailure e] -> Value
$ctoEncodingList :: forall e. ToJSON e => [StructureIntactnessFailure e] -> Encoding
toEncodingList :: [StructureIntactnessFailure e] -> Encoding
$comitField :: forall e. ToJSON e => StructureIntactnessFailure e -> Bool
omitField :: StructureIntactnessFailure e -> Bool
ToJSON)

-- |
-- [STRUCTURE RECOGNIZER CONFLICT RESOLUTION]
-- Ordering is by increasing preference between simultaneously
-- completed structures.
-- The preference heuristic is for:
--
-- 1. Primarily, larger area.
-- 2. Secondarily, lower X-Y coords (X is compared first)
--
-- Since the natural order of coordinates increases as described,
-- we need to invert it with 'Down' so that this ordering is by
-- increasing preference.
instance (Eq b, Eq a) => Ord (FoundStructure b a) where
  compare :: FoundStructure b a -> FoundStructure b a -> Ordering
compare = (Int32, Down (Cosmic Location))
-> (Int32, Down (Cosmic Location)) -> Ordering
forall a. Ord a => a -> a -> Ordering
compare ((Int32, Down (Cosmic Location))
 -> (Int32, Down (Cosmic Location)) -> Ordering)
-> (FoundStructure b a -> (Int32, Down (Cosmic Location)))
-> FoundStructure b a
-> FoundStructure b a
-> Ordering
forall b c a. (b -> b -> c) -> (a -> b) -> a -> a -> c
`on` (FoundStructure b a -> Int32
forall {b} {a}.
PositionedStructure (StructureWithGrid b a) -> Int32
f1 (FoundStructure b a -> Int32)
-> (FoundStructure b a -> Down (Cosmic Location))
-> FoundStructure b a
-> (Int32, Down (Cosmic Location))
forall b c c'. (b -> c) -> (b -> c') -> b -> (c, c')
forall (a :: * -> * -> *) b c c'.
Arrow a =>
a b c -> a b c' -> a b (c, c')
&&& FoundStructure b a -> Down (Cosmic Location)
forall {s}. PositionedStructure s -> Down (Cosmic Location)
f2)
   where
    f1 :: PositionedStructure (StructureWithGrid b a) -> Int32
f1 = AreaDimensions -> Int32
computeArea (AreaDimensions -> Int32)
-> (PositionedStructure (StructureWithGrid b a) -> AreaDimensions)
-> PositionedStructure (StructureWithGrid b a)
-> Int32
forall b c a. (b -> c) -> (a -> b) -> a -> c
. NonEmptyGrid (AtomicKeySymbol a) -> AreaDimensions
forall a. NonEmptyGrid a -> AreaDimensions
getNEGridDimensions (NonEmptyGrid (AtomicKeySymbol a) -> AreaDimensions)
-> (PositionedStructure (StructureWithGrid b a)
    -> NonEmptyGrid (AtomicKeySymbol a))
-> PositionedStructure (StructureWithGrid b a)
-> AreaDimensions
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ExtractedArea b a -> NonEmptyGrid (AtomicKeySymbol a)
forall b a. ExtractedArea b a -> NonEmptyGrid (AtomicKeySymbol a)
extractedGrid (ExtractedArea b a -> NonEmptyGrid (AtomicKeySymbol a))
-> (PositionedStructure (StructureWithGrid b a)
    -> ExtractedArea b a)
-> PositionedStructure (StructureWithGrid b a)
-> NonEmptyGrid (AtomicKeySymbol a)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. StructureWithGrid b a -> ExtractedArea b a
forall b a. StructureWithGrid b a -> ExtractedArea b a
entityGrid (StructureWithGrid b a -> ExtractedArea b a)
-> (PositionedStructure (StructureWithGrid b a)
    -> StructureWithGrid b a)
-> PositionedStructure (StructureWithGrid b a)
-> ExtractedArea b a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. PositionedStructure (StructureWithGrid b a)
-> StructureWithGrid b a
forall s. PositionedStructure s -> s
structureWithGrid
    f2 :: PositionedStructure s -> Down (Cosmic Location)
f2 = Cosmic Location -> Down (Cosmic Location)
forall a. a -> Down a
Down (Cosmic Location -> Down (Cosmic Location))
-> (PositionedStructure s -> Cosmic Location)
-> PositionedStructure s
-> Down (Cosmic Location)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. PositionedStructure s -> Cosmic Location
forall s. PositionedStructure s -> Cosmic Location
upperLeftCorner

-- | Yields coordinates that are occupied by an entity of a placed structure.
-- Cells within the rectangular bounds of the structure that are unoccupied
-- are not included.
genOccupiedCoords :: FoundStructure b a -> [Cosmic Location]
genOccupiedCoords :: forall b a. FoundStructure b a -> [Cosmic Location]
genOccupiedCoords (PositionedStructure Cosmic Location
loc StructureWithGrid b a
swg) =
  [Maybe (Cosmic Location)] -> [Cosmic Location]
forall a. [Maybe a] -> [a]
catMaybes ([Maybe (Cosmic Location)] -> [Cosmic Location])
-> (ExtractedArea b a -> [Maybe (Cosmic Location)])
-> ExtractedArea b a
-> [Cosmic Location]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. NonEmpty (Maybe (Cosmic Location)) -> [Maybe (Cosmic Location)]
forall a. NonEmpty a -> [a]
NE.toList (NonEmpty (Maybe (Cosmic Location)) -> [Maybe (Cosmic Location)])
-> (ExtractedArea b a -> NonEmpty (Maybe (Cosmic Location)))
-> ExtractedArea b a
-> [Maybe (Cosmic Location)]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Coords -> Maybe a -> Maybe (Cosmic Location))
-> NonEmptyGrid (Maybe a) -> NonEmpty (Maybe (Cosmic Location))
forall a b. (Coords -> a -> b) -> NonEmptyGrid a -> NonEmpty b
mapWithCoordsNE Coords -> Maybe a -> Maybe (Cosmic Location)
forall {f :: * -> *} {b}.
Functor f =>
Coords -> f b -> f (Cosmic Location)
f (NonEmptyGrid (Maybe a) -> NonEmpty (Maybe (Cosmic Location)))
-> (ExtractedArea b a -> NonEmptyGrid (Maybe a))
-> ExtractedArea b a
-> NonEmpty (Maybe (Cosmic Location))
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ExtractedArea b a -> NonEmptyGrid (Maybe a)
forall b a. ExtractedArea b a -> NonEmptyGrid (AtomicKeySymbol a)
extractedGrid (ExtractedArea b a -> [Cosmic Location])
-> ExtractedArea b a -> [Cosmic Location]
forall a b. (a -> b) -> a -> b
$ StructureWithGrid b a -> ExtractedArea b a
forall b a. StructureWithGrid b a -> ExtractedArea b a
entityGrid StructureWithGrid b a
swg
 where
  -- replaces an "occupied" grid cell with its location
  f :: Coords -> f b -> f (Cosmic Location)
f Coords
cellLoc f b
maybeEnt = ((Cosmic Location
loc Cosmic Location -> V2 Int32 -> Cosmic Location
`offsetBy`) (V2 Int32 -> Cosmic Location)
-> (Coords -> V2 Int32) -> Coords -> Cosmic Location
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Location -> V2 Int32
asVector (Location -> V2 Int32)
-> (Coords -> Location) -> Coords -> V2 Int32
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Coords -> Location
coordsToLoc (Coords -> Cosmic Location) -> Coords -> Cosmic Location
forall a b. (a -> b) -> a -> b
$ Coords
cellLoc) Cosmic Location -> f b -> f (Cosmic Location)
forall a b. a -> f b -> f a
forall (f :: * -> *) a b. Functor f => a -> f b -> f a
<$ f b
maybeEnt

data StaticStructureInfo b a = StaticStructureInfo
  { forall b a. StaticStructureInfo b a -> RecognizerAutomatons b a
_staticAutomatons :: RecognizerAutomatons b a
  , forall b a.
StaticStructureInfo b a -> Map SubworldName [LocatedStructure]
_staticPlacements :: Map SubworldName [LocatedStructure]
  }

makeLensesNoSigs ''StaticStructureInfo

-- | Recognition engine for statically-defined structures
staticAutomatons :: Lens' (StaticStructureInfo b a) (RecognizerAutomatons b a)

-- | A record of the static placements of structures, so that they can be
-- added to the "recognized" list upon scenario initialization
staticPlacements :: Lens' (StaticStructureInfo b a) (Map SubworldName [LocatedStructure])