icyrock.com

HomeOld blogOld blog 2

PureScript solution to Project Euler problem 67

2023-05-04 14:31

Problem details at Project Euler problem 67 page.

Test

module Euler067Test (euler67suite) where

import Prelude

import Data.Maybe (Maybe(..))
import Effect.Aff (Milliseconds(..), delay)
import Effect.Class (liftEffect)
import Euler067 (euler67)
import Test.Unit (TestSuite, suite, test)
import Test.Unit.Assert as Assert

euler67suite :: TestSuite
euler67suite =
  suite "Euler 67" do
    test "Warmup" do
      delay (Milliseconds 0.0)
      Assert.equal (pure $ Just 23) =<< (liftEffect $ euler67 "etc/067-triangle-warmup.txt")

    test "Real" do
      delay (Milliseconds 0.0)
      Assert.equal (pure $ Just 7273) =<< (liftEffect $ euler67 "etc/067-triangle-real.txt")

Solution

module Euler067 where

import Prelude

import Data.Array (concat, drop, foldl, fromFoldable, zip)
import Data.Either (Either)
import Data.Foldable (maximum)
import Data.Int (fromString)
import Data.Maybe (Maybe, maybe)
import Data.String.CodeUnits (fromCharArray)
import Data.Tuple (fst, snd)
import Effect (Effect)
import Node.Encoding (Encoding(..))
import Node.FS.Sync (readTextFile)
import Parsing (ParseError, Parser, fail, runParser)
import Parsing.Combinators (sepBy1, sepEndBy1)
import Parsing.Combinators.Array (many)
import Parsing.String (char)
import Parsing.String.Basic (digit)

parser :: Parser String (Array (Array Int))
parser =
  let pint = maybe (fail "not int") pure =<< (fromString <<< fromCharArray) <$> many digit
      pints = fromFoldable <$> sepBy1 pint (char ' ')
  in fromFoldable <$> sepEndBy1 pints (char '\n')

parse :: String -> Either ParseError (Array (Array Int))
parse = flip runParser parser

calcOne :: Array Int -> Array Int -> Array Int
calcOne xs ys =
  let es = concat [[0], xs, [0]]
      ps = zip es (drop 1 es)
      maxt t = max (fst t) (snd t)
      zs = map maxt ps
      ns = zip ys zs
      sumt t = fst t + snd t
  in map sumt ns

calc :: Array (Array Int) -> Maybe Int
calc = maximum <<< foldl calcOne [0]

euler67 :: String -> Effect (Either ParseError (Maybe Int))
euler67 file = (map calc <$> parse) <$> readTextFile UTF8 file