2022-09-26 17:37
Problem details at Project Euler problem 59 page.
module Euler059Test (euler59suite) where
import Prelude
import Effect.Class (liftEffect)
import Effect.Aff (Milliseconds(..), delay)
import Euler059 (euler59)
import Test.Unit (TestSuite, suite, test)
import Test.Unit.Assert as Assert
euler59suite :: TestSuite
euler59suite =
suite "Euler 59" do
test "Real" do
delay (Milliseconds 0.0)
Assert.equal 129448 =<< liftEffect euler59
module Euler059 where
import Prelude
import Data.Array (concat, drop, filter, head, length, range, snoc, take, zipWith)
import Data.Char (toCharCode)
import Data.Foldable (sum)
import Data.Int (fromString)
import Data.Int.Bits (xor)
import Data.Maybe (fromJust)
import Data.String (Pattern(..), split)
import Data.String.CodeUnits (toCharArray)
import Effect (Effect)
import Node.Encoding (Encoding(..))
import Node.FS.Sync (readTextFile)
import Partial.Unsafe (unsafePartial)
toCodes :: String -> Array Int
toCodes txt =
let as = split (Pattern ",") txt
in map (unsafePartial fromJust <<< fromString) as
passwords :: Int -> Array (Array Int)
passwords l =
let go :: Int -> Array (Array Int) -> Array (Array Int)
go 0 as = as
go n as =
go (n - 1) do
bs <- as
cs <- range 97 122
pure $ bs `snoc` cs
in go l [[]]
doXor :: Array Int -> Array Int -> Array Int
doXor cs ps =
let r = (length cs `div` length ps) + 1
rep 0 _ = []
rep n as = concat [as, rep (n - 1) as]
in zipWith xor cs (rep r ps)
xors :: String -> Array (Array Int)
xors txt =
let cs = toCodes txt
ps = passwords 3
in map (doXor cs) ps
isEnglish :: Array Int -> Boolean
isEnglish as =
let wc = map toCharCode <<< toCharArray
find _ [] = false
find ns bs
| take (length ns) bs == ns = true
| otherwise = find ns (drop 1 bs)
in find (wc "have") as && find (wc "the") as
findEnglish :: String -> Array Int
findEnglish = unsafePartial fromJust <<< head <<< filter isEnglish <<< xors
solve :: String -> Int
solve = sum <<< findEnglish
euler59 :: Effect Int
euler59 = do
txt <- readTextFile UTF8 "etc/059-cipher.txt"
pure $ solve txt