Skip to content

Commit

Permalink
Replace loops
Browse files Browse the repository at this point in the history
  • Loading branch information
ephemient committed Dec 2, 2024
1 parent 84a58e2 commit 9e8d439
Show file tree
Hide file tree
Showing 3 changed files with 32 additions and 37 deletions.
16 changes: 9 additions & 7 deletions hs/src/Day2.hs
Original file line number Diff line number Diff line change
Expand Up @@ -4,23 +4,25 @@
module Day2 (part1, part2) where

import Common (readEntire)
import Data.Ix (inRange)
import Control.Monad (ap, foldM_, guard)
import Data.Functor (($>))
import Data.List (inits, tails)
import Data.Maybe (isJust)
import Data.Text (Text)
import Data.Text qualified as T (lines, words)
import Data.Text.Read qualified as T (decimal)

parse :: Text -> Either String [[Int]]
parse = mapM (mapM (readEntire T.decimal) . T.words) . T.lines

isSafe, isSafe' :: [Int] -> Bool
isSafe report = all (inRange (-3, -1)) delta || all (inRange (1, 3)) delta
isSafe1, isSafe2 :: [Int] -> Bool
isSafe1 = isJust . foldM_ go EQ . (zipWith (-) `ap` drop 1)
where
delta = zipWith (-) report $ drop 1 report
isSafe' report = any isSafe [a ++ b | (a, _ : b) <- zip (inits report) (tails report)]
go k x = guard (x /= 0 && abs x <= 3 && k /= compare 0 x) $> compare x 0
isSafe2 report = any isSafe1 [a ++ b | (a, _ : b) <- zip (inits report) (tails report)]

part1 :: Text -> Either String Int
part1 input = length . filter isSafe <$> parse input
part1 input = length . filter isSafe1 <$> parse input

part2 :: Text -> Either String Int
part2 input = length . filter isSafe' <$> parse input
part2 input = length . filter isSafe2 <$> parse input
Original file line number Diff line number Diff line change
Expand Up @@ -16,24 +16,22 @@ class Day2(input: String) {
private fun isSafe1(report: IntArray): Boolean {
var decreasing = false
var increasing = false
for (i in 0..report.size - 2) {
when (report[i + 1] - report[i]) {
in -3..-1 -> decreasing = true
in 1..3 -> increasing = true
else -> return false
return (0..report.size - 2).all {
when (report[it + 1] - report[it]) {
in -3..-1 -> !increasing.also { decreasing = true }
in 1..3 -> !decreasing.also { increasing = true }
else -> false
}
}
return !(decreasing && increasing)
}

private fun isSafe2(report: IntArray): Boolean {
if (report.isEmpty()) return true
val report2 = report.copyOf(report.size - 1)
for (i in report2.lastIndex downTo 0) {
if (isSafe1(report2)) return true
report2[i] = report[i + 1]
val report2 = report.copyOfRange(1, report.size)
return isSafe1(report2) || report2.indices.any {
report2[it] = report[it]
isSafe1(report2)
}
return isSafe1(report2)
}
}
}
33 changes: 14 additions & 19 deletions rs/src/day2.rs
Original file line number Diff line number Diff line change
@@ -1,30 +1,25 @@
fn parse(data: &str) -> Vec<Vec<i32>> {
data.lines()
.flat_map(|line| {
line.split_ascii_whitespace()
.map(|level| level.parse::<i32>().ok())
.collect::<Option<Vec<_>>>()
})
.collect::<Vec<_>>()
use std::cmp::Ordering;

fn parse(data: &str) -> impl Iterator<Item = Vec<i32>> + use<'_> {
data.lines().flat_map(|line| {
line.split_ascii_whitespace()
.map(|level| level.parse::<i32>().ok())
.collect::<Option<Vec<_>>>()
})
}

fn is_safe_1(report: &[i32]) -> bool {
let mut decreasing = false;
let mut increasing = false;
report
.iter()
.zip(report.iter().skip(1))
.all(|(x, y)| match x - y {
-3..=-1 => {
decreasing = true;
!increasing
}
1..=3 => {
increasing = true;
!decreasing
.try_fold(Ordering::Equal, |cmp, (x, y)| {
if x != y && (x - y).abs() <= 3 {
Some(x.cmp(y)).filter(|cmp2| cmp != cmp2.reverse())
} else {
None
}
_ => false,
})
.is_some()
}

fn is_safe_2(report: &[i32]) -> bool {
Expand Down

0 comments on commit 9e8d439

Please sign in to comment.