import Data.Char import Data.Bits import Debug.Trace main :: IO () main = do input <- readFile "input" let st = parseState $ lines input -- print $ part1 st let n = head $ part2 st print n print $ check st n check (_, b, c, prog) a = run a b c prog 0 (length prog) [] part1 (a, b, c, prog) = run a b c prog 0 (length prog) [] -- ignore program completely and just treat it as output -- output char is X^(A>>(X^7)) with X=A&7, 16 times (=48 bit) part2 (_, _, _, prog) = crackHash 0 0 . listToNum $ prog -- oh god what madness -- generate two digits at a time for one output digit, -- then check if they're compatible with each, and with the rest of the output crackHash _ _ 0 = [0] crackHash known knownm num = let d = num .&. 7 try = [(a, 7, (a `xor` d) `shiftLI` s, 7 `shiftLI` s) | a <- [0..7], let s = a `xor` 7] valid = filter (\(d1,m1, d2,m2) -> let n = d1 .|. d2 .|. known in (n .&. m1) == d1 && (n .&. m2) == d2 && (n .&. knownm) == known ) try in concatMap (\(d1,m1, d2,m2) -> let n = d1 .|. d2 .|. known m = m1 .|. m2 .|. knownm in map (\c -> c*8 .|. n) (crackHash (s3 n) (s3 m) (s3 num)) ) valid where s3 n = n `shiftR` 3 -- no idea why i should need this crap shiftLI :: Int -> Int -> Int shiftLI = (shiftL) listToNum [x] = x listToNum (x:xs) = x + (listToNum xs)*8 run a b c prog ip maxIP output | ip >= maxIP = reverse output | otherwise = let inst = prog!!ip op = prog!!(ip+1) nip = ip+2 in case inst of 0 -> run (a `shiftR` (combo op)) b c prog nip maxIP output 1 -> run a (b `xor` op) c prog nip maxIP output 2 -> run a ((combo op) .&. 7) c prog nip maxIP output 3 -> run a b c prog (if a == 0 then nip else op) maxIP output 4 -> run a (b `xor` c) c prog nip maxIP output 5 -> run a b c prog nip maxIP (((combo op).&.7):output) 6 -> run a (a `shiftR` (combo op)) c prog nip maxIP output 7 -> run a b (a `shiftR` (combo op)) prog nip maxIP output where combo 0 = 0 combo 1 = 1 combo 2 = 2 combo 3 = 3 combo 4 = a combo 5 = b combo 6 = c digitComma c = isDigit c || c == ',' parseState ls = let [a,b,c,_,p] = map (filter digitComma) ls in (readInt a, readInt b, readInt c, readIntList ("["++p++"]")) readInt = read :: String->Int readIntList = read :: String->[Int]