87
									
								
								src/Day17.hs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										87
									
								
								src/Day17.hs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,87 @@
 | 
			
		||||
module Main where
 | 
			
		||||
 | 
			
		||||
import qualified AoC as A (extract)
 | 
			
		||||
import Data.Bits (Bits (shiftR, xor))
 | 
			
		||||
import Data.List (isSuffixOf)
 | 
			
		||||
import Text.Parsec (char, digit, many1, newline, parse, sepBy1, string)
 | 
			
		||||
import Text.Parsec.String (Parser)
 | 
			
		||||
 | 
			
		||||
data Instruction = Adv | Bxl | Bst | Jnz | Bxc | Out | Bdv | Cdv deriving (Enum, Show)
 | 
			
		||||
 | 
			
		||||
type Program = [Int]
 | 
			
		||||
 | 
			
		||||
type PC = Int
 | 
			
		||||
 | 
			
		||||
type Registers = (Int, Int, Int)
 | 
			
		||||
 | 
			
		||||
type Output = [Int]
 | 
			
		||||
 | 
			
		||||
parseProg :: Parser Program
 | 
			
		||||
parseProg = string "Program: " *> ((read <$> many1 digit) `sepBy1` char ',')
 | 
			
		||||
 | 
			
		||||
parseRegs :: Parser Registers
 | 
			
		||||
parseRegs = do
 | 
			
		||||
  a <- string "Register A: " *> (read <$> many1 digit) <* newline
 | 
			
		||||
  b <- string "Register B: " *> (read <$> many1 digit) <* newline
 | 
			
		||||
  c <- string "Register C: " *> (read <$> many1 digit) <* newline
 | 
			
		||||
  return (a, b, c)
 | 
			
		||||
 | 
			
		||||
parseInfo :: Parser (Registers, Program)
 | 
			
		||||
parseInfo = (,) <$> (parseRegs <* newline) <*> parseProg
 | 
			
		||||
 | 
			
		||||
steps :: PC -> Registers -> Program -> Output
 | 
			
		||||
steps pc regs prog = step pc regs
 | 
			
		||||
  where
 | 
			
		||||
    step :: PC -> Registers -> Output
 | 
			
		||||
    step pc regs@(a, b, c) = case drop pc prog of
 | 
			
		||||
      [] -> []
 | 
			
		||||
      ins : op : _ ->
 | 
			
		||||
        case toEnum ins of
 | 
			
		||||
          Adv -> step (pc + 2) (a `shiftR` combo, b, c)
 | 
			
		||||
          Bxl -> step (pc + 2) (a, b `xor` op, c)
 | 
			
		||||
          Bst -> step (pc + 2) (a, combo `mod` 8, c)
 | 
			
		||||
          Jnz | a /= 0 -> step op regs
 | 
			
		||||
          Jnz -> step (pc + 2) regs
 | 
			
		||||
          Bxc -> step (pc + 2) (a, b `xor` c, c)
 | 
			
		||||
          Out -> combo `mod` 8 : step (pc + 2) regs
 | 
			
		||||
          Bdv -> step (pc + 2) (a, a `shiftR` combo, c)
 | 
			
		||||
          Cdv -> step (pc + 2) (a, b, a `shiftR` combo)
 | 
			
		||||
        where
 | 
			
		||||
          combo :: Int
 | 
			
		||||
          combo = case op of
 | 
			
		||||
            0 -> 0
 | 
			
		||||
            1 -> 1
 | 
			
		||||
            2 -> 2
 | 
			
		||||
            3 -> 3
 | 
			
		||||
            4 -> a
 | 
			
		||||
            5 -> b
 | 
			
		||||
            6 -> c
 | 
			
		||||
            _ -> error "invalid operand"
 | 
			
		||||
 | 
			
		||||
--------------------------------------------------------------
 | 
			
		||||
-- Will only work given the following conditions are true   --
 | 
			
		||||
-- 1. There is only a single loop at the end of program     --
 | 
			
		||||
-- 2. A is right shifted by 3 every loop                    --
 | 
			
		||||
-- 3. B is the value being printed                          --
 | 
			
		||||
-- 4. Based on the instructions, B is deterministic given A --
 | 
			
		||||
--------------------------------------------------------------
 | 
			
		||||
part2 :: Program -> Int
 | 
			
		||||
part2 prog = go 0
 | 
			
		||||
  where
 | 
			
		||||
    go :: Int -> Int
 | 
			
		||||
    go a
 | 
			
		||||
      | output == prog = a
 | 
			
		||||
      | output `isSuffixOf` prog = go $ a * 8
 | 
			
		||||
      | otherwise = go $ a + 1
 | 
			
		||||
      where
 | 
			
		||||
        output = steps 0 (a, 0, 0) prog
 | 
			
		||||
 | 
			
		||||
main :: IO ()
 | 
			
		||||
main =
 | 
			
		||||
  do
 | 
			
		||||
    raw <- readFile "./inputs/day17.in"
 | 
			
		||||
 | 
			
		||||
    let (regs, prog) = A.extract $ parse parseInfo "" raw
 | 
			
		||||
 | 
			
		||||
    putStr "Part 1: " >> print (steps 0 regs prog)
 | 
			
		||||
    putStr "Part 2: " >> print (part2 prog)
 | 
			
		||||
		Reference in New Issue
	
	Block a user