import AoC
import Data.Text (Text)
import qualified Data.Text.IO as TIO
-import Data.Attoparsec.Text -- hiding (take)
+import Data.Attoparsec.Text hiding (take, takeWhile)
import Control.Applicative
import Data.List
import qualified Data.Map.Strict as M
import Data.Maybe
-import Control.Monad.State.Strict
-data Spring = Unknown | Damaged | Operational deriving (Show, Eq)
-data Record = Record [Spring] [Int] deriving (Show)
+data Spring = Unknown | Damaged | Operational deriving (Show, Eq, Ord)
+data Record = Record [Spring] [Int] deriving (Show, Eq, Ord)
type Cache = M.Map Record Int
-- type CacheState = State Cache
-- print $ fmap countViableAssignments records
print $ part1 records
print $ unfoldRecord $ head records
- print $ part2 records
+ -- print $ part2 records
-part1, part2 :: [Record] -> Int
+part1 :: [Record] -> Int
part1 = sum . fmap countViableAssignments
-part2 = sum . fmap (countViableAssignments . unfoldRecord)
+-- part2 = sum . fmap (countViableAssignments . unfoldRecord)
unfoldRecord :: Record -> Record
unfoldRecord (Record springs signature) = Record uSprings uSignature
uSignature = concat $ replicate 5 signature
-countViable :: Record -> CacheState Int
+
+initialCache :: Record -> Cache
+initialCache (Record springs signature) = M.union lastOperational cache0
+ where cache0 = M.union sprs sigs
+ sprs = M.fromList $ fmap (\s -> (Record s [], 0)) $ tails springs
+ sigs = M.fromList $ fmap (\g -> (Record [] g, 0)) $ tails signature
+ lastOperationalChunk =
+ reverse $ takeWhile isPossOperational $ reverse springs
+ lastOperational =
+ M.fromList $ fmap (\s -> (Record s [], 1)) $ tails lastOperationalChunk
+
+isPossOperational :: Spring -> Bool
+isPossOperational Operational = True
+isPossOperational Unknown = True
+isPossOperational _ = False
+
+isPossDamaged :: Spring -> Bool
+isPossDamaged Damaged = True
+isPossDamaged Unknown = True
+isPossDamaged _ = False
+
+possibleDamagedChunk :: [Spring] -> Int -> Bool
+possibleDamagedChunk springs n =
+ isDamagedChunk && ((null afterChunk) || (possOperational $ head afterChunk))
+ where isDamagedChunk = (length $ filter isPossDamaged $ take n springs) == n
+ afterChunk = take 1 $ drop n springs
+
+
+-- countViable previousSprings (Record (s:springs) (g:signature)) =
+
+
+-- count: either consume this group or not
+
+
+-- cache is how many ways to assign unknowns, leaving this partial record.
+-- first item of springs is unknown or damaged
+-- count = count_consuming_group + count_leaving_group
+-- if first spring is damaged: count = count_consuming_group
+
+
+
+-- if first spring is damaged and next few springs can match next group:
+-- consume springs (including all following operational ones), consume group
+-- Add to cache: record' -> cache ! original
+-- return countViable record'
+-- if first spring is unknown
+-- assume it's damaged, consume springs, consume group
+
-countViable previousSprings (Record (s:springs) (g:signature)) =
--- if next few springs can match next group:
-- countViable (springs after group) (tail groups) + countViable (tail springs) groups
-- else
-- countViable (tail springs) groups