never executed always true always false
    1 {-|
    2 Module:      Y2015.D07
    3 Description: Advent of Code Day 07 Solutions.
    4 License:     MIT
    5 Maintainer:  @tylerjl
    6 
    7 Solutions to the day 07 set of problems for <adventofcode.com>.
    8 -}
    9 
   10 module Y2015.D07
   11     ( wire
   12     , circuitParser
   13     , parseCircuits
   14     , override
   15 ) where
   16 
   17 import Y2015.Util (regularParse, intParser)
   18 
   19 import           Control.Applicative   ((<|>))
   20 import           Data.Bits             ((.&.), (.|.), shift, complement)
   21 import           Data.Function.Memoize (memoize)
   22 import           Data.Map.Strict       (Map)
   23 import qualified Data.Map.Strict  as   M
   24 import           Data.Word             (Word16)
   25 import           Text.Parsec.Char      (digit, letter, endOfLine)
   26 import           Text.Parsec.String    (Parser)
   27 import           Text.Parsec
   28     ( lookAhead
   29     , many
   30     , many1
   31     , optional
   32     , skipMany
   33     , skipMany1
   34     , space
   35     , string
   36     , try)
   37 
   38 type Wire = String
   39 
   40 data Atom = Val Word16 | Var String
   41           deriving (Show)
   42 
   43 data Gate = Singleton Atom
   44           | And       Atom Atom
   45           | Or        Atom Atom
   46           | LShift    Atom Int
   47           | RShift    Atom Int
   48           | Not       Atom
   49           deriving (Show)
   50 
   51 data Instruction = Instruction Gate Wire
   52                  deriving (Show)
   53 
   54 -- |Parsec parser for list of 'Instruction's
   55 circuitParser :: Parser [Instruction] -- ^ Parser
   56 circuitParser = many (pInstruction <* optional endOfLine)
   57 
   58 pInstruction :: Parser Instruction
   59 pInstruction = Instruction <$> pGate <*> pWire
   60 
   61 pGate :: Parser Gate
   62 pGate =  try (Singleton <$> atom <* lookAhead arrow)
   63      <|> try (And       <$> atom <* gate "AND"    <*> atom)
   64      <|> try (Or        <$> atom <* gate "OR"     <*> atom)
   65      <|> try (LShift    <$> atom <* gate "LSHIFT" <*> bits)
   66      <|> try (RShift    <$> atom <* gate "RSHIFT" <*> bits)
   67      <|> try (Not       <$          gate "NOT"    <*> atom)
   68 
   69 pWire :: Parser Wire
   70 pWire = arrow *> many1 letter
   71 
   72 gate :: String -> Parser ()
   73 gate s = skipMany space *> string s *> skipMany1 space
   74 
   75 bits :: Parser Int
   76 bits = intParser
   77 
   78 atom :: Parser Atom
   79 atom =  try (Var <$> many1 letter)
   80     <|> try (Val .read <$> many1 digit)
   81 
   82 arrow :: Parser ()
   83 arrow = skipMany1 space *> string "->" *> skipMany1 space
   84 
   85 voltageOn :: Map String Gate -> String -> Word16
   86 voltageOn m = resolve
   87     where eval :: String -> Word16
   88           eval wire' = case M.lookup wire' m of
   89                        Just (Singleton x) -> atom' x
   90                        Just (And x y)     -> atom' x .&. atom' y
   91                        Just (Or x y)      -> atom' x .|. atom' y
   92                        Just (LShift x i)  -> shift (atom' x) i
   93                        Just (RShift x i)  -> shift (atom' x) (-i)
   94                        Just (Not x)       -> complement (atom' x)
   95                        Nothing            -> 0
   96           resolve = memoize eval
   97           atom' (Val i) = i
   98           atom' (Var v) = resolve v
   99 
  100 -- |Constructs then returns resulting voltage from wiring spec
  101 wire :: String        -- ^ Wire to find voltage on
  102      -> [Instruction] -- ^ List of instructions
  103      -> Word16        -- ^ Resulting voltage on indicated wire
  104 wire s = flip voltageOn s . M.fromList . map toPair
  105     where toPair (Instruction g w) = (w, g)
  106 
  107 -- |Helper function to parse 'Instruction's
  108 parseCircuits :: String                            -- ^ Input string
  109               -> [Instruction] -- ^ Either parse error or 'Instruction's
  110 parseCircuits = either err suc . regularParse circuitParser
  111   where err = error . show
  112         suc r = r
  113 
  114 -- |Inject a manual instruction.
  115 override :: Word16      -- ^ Value to inject into 'Instruction'.
  116          -> Instruction -- ^ Resulting 'Instruction'.
  117 override s = Instruction (Singleton (Val s)) "b"