Skip to content

Commit

Permalink
wip chunk combinations
Browse files Browse the repository at this point in the history
  • Loading branch information
kostmo committed Nov 9, 2024
1 parent 5425231 commit 491017c
Show file tree
Hide file tree
Showing 2 changed files with 106 additions and 60 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -69,8 +69,16 @@ data RowMismatchReason e
EmptyIntersection
deriving (Functor, Generic, ToJSON)

data WrongRecurrenceCountExplanation = WrongRecurrenceCountExplanation
{ foundCount :: Int
, foundMembers :: NonEmpty Int
, expectedCount :: Int
, expectedMembers :: NonEmpty Int
}
deriving (Generic, ToJSON)

data ChunkMismatchReason
= WrongNumberOfRecurrences Int Int
= WrongNumberOfRecurrences WrongRecurrenceCountExplanation
| Misalignment (NonEmpty Int)
deriving (Generic, ToJSON)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -163,14 +163,101 @@ determineFoundChunksOffset ::
determineFoundChunksOffset (FoundAndExpectedChunkPositions found expected) = do
unless (length found == length expected) $
Left $
WrongNumberOfRecurrences (length found) (length expected)
WrongNumberOfRecurrences $
WrongRecurrenceCountExplanation
(length found)
found
(length expected)
expected
unless (allEqual $ NE.toList differences) $
Left $
Misalignment differences
return $ NE.head differences
where
differences = NE.zipWith subtract expected found

-- | This runs once per non-overlapping subset of found chunks
checkChunksCombination ::
(Monad m, Hashable a, Eq b) =>
(Cosmic Location -> m (Maybe a)) ->
Cosmic Location ->
RecognitionState b a ->
InspectionOffsets ->
NE.NonEmpty (RowChunkMatchingReference b a) ->
[Position (NE.NonEmpty a)] ->
WriterT [SearchLog a] m (RecognitionState b a)
checkChunksCombination
entLoader
cLoc
rState
horizontalOffsets
pwMaps
candidatesChunked = do
tell . pure . FoundPiecewiseChunks . map swap $ HM.toList foundRowChunksLookup

let (candidateFailures, candidateExpected) =
partitionEithers $
map subsetChecker $
NE.toList pwMaps

tell . pure . ChunkFailures $ candidateFailures

tell . pure . ChunksMatchingExpected $
map (modifyChunkedRowMatch $ fmap $ getName . originalDefinition . wholeStructure) candidateExpected

let structurePositionsToCheck = map mkFoundStructure candidateExpected
intactStructures <- filterM validateIntactness2d structurePositionsToCheck

registerStructureMatches intactStructures rState
where
foundRowChunksLookup = binTuplesHM $ map (pVal &&& pIndex) candidatesChunked

mkFoundStructure x =
FoundStructure
(wholeStructure $ chunkStructure $ foundChunkRow x)
(cLoc `offsetBy` structurePositionOffset (foundChunkRow x))

validateIntactness2d fs = do
intactnesss <- lift $ ensureStructureIntact entLoader fs
tell . pure . ChunkIntactnessVerification $
IntactPlacementLog
intactnesss
(getName . originalDefinition . structureWithGrid $ fs)
(upperLeftCorner fs)
return intactnesss

subsetChecker (RowChunkMatchingReference r chunkPositionMap) =
left (ChunkMatchFailureReason $ getName . originalDefinition . wholeStructure $ r) $ do
let isKeysSubset = referenceChunksKeys `HS.isSubsetOf` foundChunksKeys
unless isKeysSubset . Left $
NoKeysSubset $
(FoundChunkComparison `on` HS.toList) foundChunksKeys referenceChunksKeys

let theIntersection =
HM.intersectionWith
FoundAndExpectedChunkPositions
foundRowChunksLookup
chunkPositionMap

nonEmptyPairs <-
maybeToEither EmptyIntersection $
NE.nonEmpty $
HM.toList theIntersection

rowOffset <- left ChunkMismatchReason $ determineFoundRowOffset nonEmptyPairs

let horizontalStructurePosition = fromIntegral rowOffset + getMin (startOffset horizontalOffsets)

return $
ChunkedRowMatch
(map swap $ HM.toList theIntersection)
(FoundRowFromChunk rowOffset (rowIndex r) (V2 horizontalStructurePosition (rowIndex r)) r)
where
foundChunksKeys = HM.keysSet foundRowChunksLookup
referenceChunksKeys = HM.keysSet chunkPositionMap

modifyChunkedRowMatch f (ChunkedRowMatch x y) = ChunkedRowMatch x (f y)

-- | This is the first (one-dimensional) stage
-- in a two-stage (two-dimensional) search.
--
Expand Down Expand Up @@ -200,69 +287,20 @@ registerRowMatches entLoader cLoc (AutomatonNewInfo horizontalOffsets _ pwMatche
tell . pure . ExpectedChunks $ NE.map (HM.keys . confirmationMap) pwMaps

let candidatesChunked = findAll pwSM entitiesRow
foundRowChunksLookup = binTuplesHM $ map (pVal &&& pIndex) candidatesChunked

tell . pure . FoundPiecewiseChunks . map swap $ HM.toList foundRowChunksLookup
-- TODO: Find all combinations of non-overlapping chunks,
-- then run 'checkChunksCombination' for each combination.

let (candidateFailures, candidateExpected) =
partitionEithers $
map (subsetChecker foundRowChunksLookup) $
NE.toList pwMaps

tell . pure . ChunkFailures $ candidateFailures

tell . pure . ChunksMatchingExpected $
map (modifyChunkedRowMatch $ fmap $ getName . originalDefinition . wholeStructure) candidateExpected

let structurePositionsToCheck = map mkFoundStructure candidateExpected
intactStructures <- filterM validateIntactness2d structurePositionsToCheck

registerStructureMatches intactStructures rState
checkChunksCombination
entLoader
cLoc
rState
horizontalOffsets
pwMaps
candidatesChunked
where
registry = rState ^. foundStructures

mkFoundStructure x =
FoundStructure
(wholeStructure $ chunkStructure $ foundChunkRow x)
(cLoc `offsetBy` structurePositionOffset (foundChunkRow x))

validateIntactness2d fs = do
intactnesss <- lift $ ensureStructureIntact entLoader fs
tell . pure . ChunkIntactnessVerification $
IntactPlacementLog
intactnesss
(getName . originalDefinition . structureWithGrid $ fs)
(upperLeftCorner fs)
return intactnesss

subsetChecker foundRowChunksLookup (RowChunkMatchingReference r chunkPositionMap) =
left (ChunkMatchFailureReason $ getName . originalDefinition . wholeStructure $ r) $ do
let isKeysSubset = referenceChunksKeys `HS.isSubsetOf` foundChunksKeys
unless isKeysSubset . Left $
NoKeysSubset $
(FoundChunkComparison `on` HS.toList) foundChunksKeys referenceChunksKeys

let theIntersection =
HM.intersectionWith
FoundAndExpectedChunkPositions
foundRowChunksLookup
chunkPositionMap

nonEmptyPairs <- maybeToEither EmptyIntersection $ NE.nonEmpty $ HM.toList theIntersection
rowOffset <- left ChunkMismatchReason $ determineFoundRowOffset nonEmptyPairs

let horizontalStructurePosition = fromIntegral rowOffset + getMin (startOffset horizontalOffsets)

return $
ChunkedRowMatch
(map swap $ HM.toList theIntersection)
(FoundRowFromChunk rowOffset (rowIndex r) (V2 horizontalStructurePosition (rowIndex r)) r)
where
foundChunksKeys = HM.keysSet foundRowChunksLookup
referenceChunksKeys = HM.keysSet chunkPositionMap

modifyChunkedRowMatch f (ChunkedRowMatch x y) = ChunkedRowMatch x (f y)

-- |
-- We only allow an entity to participate in one structure at a time,
-- so multiple matches require a tie-breaker.
Expand Down

0 comments on commit 491017c

Please sign in to comment.