VegOwOtenks

joined 8 months ago
[โ€“] VegOwOtenks 2 points 1 month ago* (last edited 1 month ago)

Haskell

It's more complicated than it needs to be, could've done the first part just like the second.
Also it takes one second (!) to run it .-.

import Data.Maybe as Maybe
import Data.List as List
import Control.Arrow hiding (first, second)

parseRule :: String -> (Int, Int)
parseRule s = (read . take 2 &&& read . drop 3) s

replace t r c = if t == c then r else c

parse :: String -> ([(Int, Int)], [[Int]])
parse s = (map parseRule rules, map (map read . words) updates)
        where
                rules = takeWhile (/= "") . lines $ s
                updates = init . map (map (replace ',' ' ')) . drop 1 . dropWhile (/= "") . lines $ s

validRule (pairLeft, pairRight) (ruleLeft, ruleRight)
        | pairLeft == ruleRight && pairRight == ruleLeft = False
        | otherwise = True

validatePair rs p = all (validRule p) rs

validateUpdate rs u = all (validatePair rs) pairs
        where 
                pairs = List.concatMap (\ t -> map (head t, ) (tail t)) . filter (length >>> (> 1)) . tails $ u

middleElement :: [a] -> a
middleElement us = (us !!) $ (length us `div` 2)

part1 (rs, us) = sum . map (middleElement) . filter (validateUpdate rs) $ us

insertOrderly rs i is = insertOrderly' frontRules i is
        where
                frontRules = filter (((== i) . fst)) rs

insertOrderly' _  i [] = [i]
insertOrderly' rs i (i':is)
        | any (snd >>> (== i')) rs = i : i' : is
        | otherwise = i' : insertOrderly' rs i is

part2 (rs, us) = sum . map middleElement . Maybe.mapMaybe ((orderUpdate &&& id) >>> \ p -> if (fst p /= snd p) then Just $ fst p else Nothing) $ us
        where
                orderUpdate = foldr (insertOrderly rs) []

main = getContents >>= print . (part1 &&& part2) . parse
[โ€“] VegOwOtenks 4 points 1 month ago

I struggled a lot more when doing list slices that I would've liked to

Haskell


import Data.List qualified as List

collectDiagonal :: [String] -> Int -> Int -> String
collectDiagonal c y x
        | length c > y && length (c !! y) > x = c !! y !! x : collectDiagonal c (y+1) (x+1)
        | otherwise = []

part1 c = do
        let forwardXMAS  = map (length . filter (List.isPrefixOf "XMAS") . List.tails) $ c
        let backwardXMAS = map (length . filter (List.isPrefixOf "XMAS") . List.tails . reverse) $ c
        let downwardXMAS  = map (length . filter (List.isPrefixOf "XMAS") . List.tails ) . List.transpose $ c
        let upwardXMAS = map (length . filter (List.isPrefixOf "XMAS") . List.tails . reverse ) . List.transpose $ c
        let leftSideDiagonals = map (\ y -> collectDiagonal c y 0) [0..length c]
        let leftTopDiagonals = map (\ x -> collectDiagonal c 0 x) [1..(length . List.head $ c)]
        let leftDiagonals = leftSideDiagonals ++ leftTopDiagonals
        let rightSideDiagonals = map (\ y -> collectDiagonal (map List.reverse c) y 0) [0..length c]
        let rightTopDiagonals = map (\ x -> collectDiagonal (map List.reverse c) 0 x) [1..(length . List.head $ c)]
        let rightDiagonals = rightSideDiagonals ++ rightTopDiagonals
        let diagonals = leftDiagonals ++ rightDiagonals

        let diagonalXMAS = map (length . filter (List.isPrefixOf "XMAS") . List.tails) $ diagonals
        let reverseDiagonalXMAS = map (length . filter (List.isPrefixOf "XMAS") . List.tails . reverse) $ diagonals

        print . sum $ [sum forwardXMAS, sum backwardXMAS, sum downwardXMAS, sum upwardXMAS, sum diagonalXMAS, sum reverseDiagonalXMAS]
        return ()

getBlock h w c y x = map (take w . drop x) . take h . drop y $ c

isXBlock b = do
        let diagonal1 = collectDiagonal b 0 0
        let diagonal2 = collectDiagonal (map List.reverse b) 0 0

        diagonal1 `elem` ["SAM", "MAS"] && diagonal2 `elem` ["SAM", "MAS"]

part2 c = do
        
        let lineBlocks = List.map (getBlock 3 3 c) [0..length c - 1]
        let groupedBlocks = List.map (flip List.map [0..(length . head $ c) - 1]) lineBlocks

        print . sum . map (length . filter isXBlock) $ groupedBlocks

        return ()

main = do
        c <- lines <$> getContents

        part1 c
        part2 c

        return ()
[โ€“] VegOwOtenks 2 points 1 month ago (2 children)

Love to see you chewing through this parsing problem in Haskell, I didn't dare use Parsec because I wasn't confident enough.
Why did you decide to have a strict definition of Mul !Int !Int?

[โ€“] VegOwOtenks 5 points 1 month ago (3 children)

I couldn't figure it out in haskell, so I went with bash for the first part

Shell

cat example | grep -Eo "mul\([[:digit:]]{1,3},[[:digit:]]{1,3}\)" | cut -d "(" -f 2 | tr -d ")" | tr "," "*" | paste -sd+ | bc

but this wouldn't rock anymore in the second part, so I had to resort to python for it

Python

import sys

f = "\n".join(sys.stdin.readlines())

f = f.replace("don't()", "\ndon't()\n")
f = f.replace("do()", "\ndo()\n")

import re

enabled = True
muls = []
for line in f.split("\n"):
    if line == "don't()":
        enabled = False
    if line == "do()":
        enabled = True
    if enabled:
        for match in re.finditer(r"mul\((\d{1,3}),(\d{1,3})\)", line):
            muls.append(int(match.group(1)) * int(match.group(2)))
        pass
    pass

print(sum(muls))
[โ€“] VegOwOtenks 7 points 1 month ago (3 children)

How do you write this, not conceptually but physically. Do you have a char picker open at all times?

[โ€“] VegOwOtenks 4 points 1 month ago (3 children)

Love to see your haskell solutions!

I am so far very amazed with the compactness of your solutions, your lessOne is very much mind-Bending. I have never used or seen <$> before, is it a monadic $?

Also I can't seem to find your logic for this safety condition: The levels are either all increasing or all decreasing, did you figure that it wasn't necessary?

[โ€“] VegOwOtenks 5 points 1 month ago

Haskell

runningDifference :: [Int] -> [Int]
runningDifference (a:[]) = []
runningDifference (a:b:cs) = a - b : (runningDifference (b:cs))

isSafe :: [Int] -> Bool
isSafe ds = (all (> 0) ds || all (< 0) ds) && (all (flip elem [1, 2, 3] . abs) ds) 

isSafe2 :: [Int] -> Bool
isSafe2 ds = any (isSafe2') (zip [0..length ds] (cycle [ds]))

isSafe2' (i, ls) = isSafe . runningDifference $ list
        where
                list = dropIndex i ls

dropIndex _ []     = []
dropIndex 0 (a:as) = dropIndex (-1) as
dropIndex i (a:as) = a : dropIndex (i - 1) as

main = do
        c <- getContents
        let reports = init . lines $ c
        let levels  = map (map read . words) reports :: [[Int]]
        let differences = map runningDifference levels
        let safety = map isSafe differences
        let safety2 = map isSafe2 levels

        putStrLn . show . length . filter (id) $ safety
        putStrLn . show . length . filter (id) $ safety2

        return ()

Took me way too long to figure out that I didn't have to drop one of them differences but the initial Number

[โ€“] VegOwOtenks 1 points 1 month ago

Python

ids = """<multiline input string>"""
ids = [pair.split(" ") for pair in ids.split("\n")]
left = [int(t[0]) for t in ids]
right = [int(t[-1]) for t in ids]
left.sort()
right.sort()
print(sum(abs(l - r) for l, r in zip(left, right)))

# 2
s = 0
for l in left:
    s += right.count(l) * l
print(s)

Lost a minute because I forgot about abs .-.

[โ€“] VegOwOtenks 1 points 1 month ago

Some Mixture of Haskell and Python and maybe Rust if my friends get me to join them.

[โ€“] VegOwOtenks 17 points 2 months ago (3 children)

@[email protected] @[email protected] @[email protected]
Sorry for the tags, but otherwise I would have had to respond to all your comments individually.

I also wanted to read on, so I searched for the book and found a page where it was possible to 'read a preview'

[โ€“] VegOwOtenks 1 points 3 months ago (1 children)

You could wrap the entirety of your file in a monster macro but you'd still have to assign the macro result to a variable you need to register, which doesn't sound viable to me at least.

Maybe you can use a script that would extract all the trait implementations and create the boilerplate glue code for you, something like this:

grep --recursive --only-matching "impl PluginFunction for \w*" functions/ | sed --quiet "s/functions\/\(.*\)\.rs:impl PluginFunction for \(\w*\)/crate::functions::\1::\2{}.register(\&mut functions_map)/p"

I tried to recreate your situation locally but it may not match perfectly, maybe you'll have to adjust it a little. When I run it on my file tree which looks like this

functions
โ”œโ”€โ”€ attr.rs
โ”œโ”€โ”€ export.rs
โ””โ”€โ”€ render.rs

1 directory, 3 files

where every file has a content like this

// comment

pub struct MyAttrStructName {}

impl PluginFunction for MyAttrStructName {

}

Then I receive the following output:

crate::functions::attr::MyAttrStructName{}.register(&mut functions_map)
crate::functions::export::MyExportStructName{}.register(&mut functions_map)
crate::functions::render::MyRenderStructName{}.register(&mut functions_map)
[โ€“] VegOwOtenks 24 points 6 months ago (1 children)

You can use backreferences \1 \2 etc. but you can also give them names explicitly.
it looks like this: (?<name>inner-regex)
Some flavors support it, kotlins doesn't apparently.

view more: โ€น prev next โ€บ