Toot

Written by VegOwOtenks@lemmy.world on 2024-12-24 at 11:08

Haskell

Part 1 was trivial, just apply the operations and delay certain ones until you have all the inputs you need.

Code

haskell import Control.Arrow import Data.Bits import Numeric import qualified Data.Char as Char import qualified Data.List as List import qualified Data.Map as Map parse s = (Map.fromList inputs, equations) where ls = lines s inputs = map (take 3 &&& (== “1”) . drop 5) . takeWhile (/= “”) $ ls equations = map words . filter (/= “”) . tail . dropWhile (/= “”) $ ls operations = Map.fromList [ (“AND”, (&&)) , (“XOR”, xor) , (“OR”, (||)) ] solveEquations is [] = is solveEquations is (e:es) | is Map.!? input1 == Nothing = solveEquations is (es ++ [e]) | is Map.!? input2 == Nothing = solveEquations is (es ++ [e]) | otherwise = solveEquations (Map.insert output (opfunc value1 value2) is) es where value1 = is Map.! input1 value2 = is Map.! input2 opfunc = operations Map.! operation (input1:operation:input2:_:output:[]) = e wireNumber prefix = List.filter ((prefix List.isPrefixOf) . fst) >>> flip zip [0…] >>> List.filter (snd . fst) >>> List.map ((2 ^ ). snd) >>> sum part1 = uncurry solveEquations >>> Map.toList >>> wireNumber “z” part2 (is, es) = List.intercalate “,” . List.sort . words $ “z08 ffj dwp kfm z22 gjh jdr z31” main = getContents >>= print . (part1 &&& part2) . parse

For part 2 I tried symbolic solving to detect discrepancies but I wouldn’t achieve anything with it.

SymbolicEquationhaskell data SymbolicEquation = Single { eqName :: String } | Combine { eqName :: String , eqOperation :: String , eqLeft :: SymbolicEquation , eqRight :: SymbolicEquation } deriving (Eq) instance Show SymbolicEquation where show (Single name) = name show (Combine name op l r) = “(” ++ name ++ "= " ++ show l ++ " " ++ op ++ " " ++ show r ++ “)” symbolicSolve is [] = is symbolicSolve is (e:es) | is Map.!? input1 == Nothing = symbolicSolve is (es ++ [e]) | is Map.!? input2 == Nothing = symbolicSolve is (es ++ [e]) | otherwise = symbolicSolve (Map.insert output (Combine output operation value1 value2) is) es where value1 = is Map.! input1 value2 = is Map.! input2 (input1:operation:input2:_:output:[]) = e

My solution was to use the dotEngine-function to translate the operations into a digraph in graphviz-style which I simply plotted and searched through using a python script.

dotEnginehaskell dotEngine (input1:operation:input2:_:output:[]) = [ input1 ++ " -> " ++ output ++ " [ label=" ++ operation ++ “];” , input2 ++ " -> " ++ output ++ " [ label=" ++ operation ++ “];” ]

I took a loook at the initial graph which was a vertical line with a few exception which I figured would be the misordered wires.

I did try some hardware-simulations in the far past to build bit-adders which helped me recognize patterns like carry calculation.

First I replaced all occurences of x__ XOR y__ -> w with x__ XOR y__ -> xor__ to recognize them more easily. The same with AND of xs and ys.

Using the following script I would then use some Regex to search for the rules that corresponded to carry calculations or structures I knew. The script would break exactly four times and I would then figure out what to switch by hand through looking at the updated graphViz.

Please excuse the bad coding style in the script, I had written it on the ipython-REPL.

python scriptpython3 r = open(“input”).read() for i in range(2, 45): prevI = str(i - 1).zfill(2) I = str(i).zfill(2) forward = f"xor{I} AND carry{prevI} -> (\w+)" backward = f"carry{prevI} AND xor{I} -> (\w+)" m1 = re.search(forward, r) m2 = re.search(backward, r) if m1 is None and m2 is None: print(forward, backward) break m = m1 or m2 r = r.replace(m.group(1), f"combinedCarry{I}“) forward = f"and{I} OR combinedCarry{I} -> (\w+)” backward = f"combinedCarry{I} OR and{I} -> (\w+)" m1 = re.search(forward, r) m2 = re.search(backward, r) if m1 is None and m2 is None: print(forward, backward) break m = m1 or m2 r = r.replace(m.group(1), f"carry{I}") open(“input”, “w”).write()

When solving such a swapped wire problem I would then use my haskell function to plot it out again and stare at it for a few minutes until I understood wich parts belonged where.

The last one looked like this

In this one I needed to switch jdr and carry31 to make it work.

=> More informations about this toot | View the thread | More toots from VegOwOtenks@lemmy.world

Mentions

=> View CameronDev@programming.dev profile

Tags

Proxy Information
Original URL
gemini://mastogem.picasoft.net/toot/113707483925838967
Status Code
Success (20)
Meta
text/gemini
Capsule Response Time
375.788945 milliseconds
Gemini-to-HTML Time
1.322864 milliseconds

This content has been proxied by September (3851b).