Haskell version using megaparsec
authorNeil Smith <neil.git@njae.me.uk>
Mon, 17 Sep 2018 16:25:25 +0000 (17:25 +0100)
committerNeil Smith <neil.git@njae.me.uk>
Mon, 17 Sep 2018 16:25:25 +0000 (17:25 +0100)
src/task1/task1-mpc.hs [new file with mode: 0644]
src/task1/task1.hs
stack.yaml
summerofcode2018soln.cabal

diff --git a/src/task1/task1-mpc.hs b/src/task1/task1-mpc.hs
new file mode 100644 (file)
index 0000000..a8a3ccb
--- /dev/null
@@ -0,0 +1,113 @@
+{-# LANGUAGE OverloadedStrings #-}
+
+import Data.List (foldl')        -- import the strict fold
+
+import Data.Text (Text)
+-- import qualified Data.Text as T
+import qualified Data.Text.IO as TIO
+
+import Data.Void (Void)
+
+import Text.Megaparsec -- hiding (State)
+import Text.Megaparsec.Char
+import qualified Text.Megaparsec.Char.Lexer as L
+import qualified Control.Applicative as CA
+
+
+-- number of steps
+type Distance = Int
+type Position = (Int, Int)
+
+-- the directions. See below for functions for turning
+data Direction = North | East | South | West 
+    deriving (Enum, Show, Bounded, Eq)
+
+-- direction, easting, northing
+data Mowmaster = Mowmaster { direction :: Direction 
+                           , position :: Position
+                           } deriving (Show, Eq)
+
+-- one instruction for the mowmaster
+data Instruction =   Forward Distance
+                   | Clockwise 
+                   | Anticlockwise
+                   | Comment String
+    deriving (Show, Eq)
+
+
+main :: IO ()
+main = do 
+        instruction_text <- TIO.readFile "data/01-mowmaster.txt"
+        let instructions = successfulParse instruction_text
+        print $ part1 instructions
+        print $ part2 instructions
+
+part1 :: [Instruction] -> Int
+part1 = length 
+
+part2 :: [Instruction] -> Int
+part2 instructions = finalDistance $ executeAll instructions
+    where executeAll = foldl' execute initialMowmaster
+
+initialMowmaster = Mowmaster North (0, 0)
+
+
+-- Calculate manhattan distance from start to this state
+finalDistance :: Mowmaster -> Int
+finalDistance m = (abs e) + (abs n)
+    where (e, n) = position m
+
+
+-- Make one move
+execute :: Mowmaster -> Instruction -> Mowmaster
+execute m (Forward s)    = m {position  = forward s (direction m) (position m)}
+execute m  Clockwise     = m {direction = turnCW (direction m)}
+execute m  Anticlockwise = m {direction = turnACW (direction m)}
+execute m  _ = m
+
+-- Move in the current direction
+forward :: Int -> Direction -> Position -> Position
+forward s North (e, n) = (e, n+s)
+forward s South (e, n) = (e, n-s)
+forward s West  (e, n) = (e-s, n)
+forward s East  (e, n) = (e+s, n)
+
+
+-- | a `succ` that wraps 
+turnCW :: (Bounded a, Enum a, Eq a) => a -> a 
+turnCW dir | dir == maxBound = minBound
+           | otherwise       = succ dir
+
+-- | a `pred` that wraps
+turnACW :: (Bounded a, Enum a, Eq a) => a -> a
+turnACW dir | dir == minBound = maxBound
+            | otherwise       = pred dir
+
+
+-- Parse the input file
+
+type Parser = Parsec Void Text
+
+-- treat comment lines as whitespace
+sc :: Parser ()
+sc = L.space space1 lineComment CA.empty
+    where lineComment = L.skipLineComment "#"
+
+lexeme  = L.lexeme sc
+integer = lexeme L.decimal
+symb = L.symbol sc
+
+-- instructions is some optional space followed by many instructions
+instrsP = optional sc *> many instrP
+instrP = forwardP <|> cwP <|> acwP
+
+-- parse each instruction
+forwardP = Forward <$> (symb "F" *> integer)
+cwP = Clockwise <$ symb "C"
+acwP = Anticlockwise <$ symb "A"
+
+successfulParse :: Text -> [Instruction]
+successfulParse input = 
+        case parse instrsP "input" input of
+                Left  _error -> [] -- TIO.putStr $ T.pack $ parseErrorPretty err
+                Right instrs  -> instrs
\ No newline at end of file
index 200d538afd1fb1af0a401e81876003baf38fd865..071fe68f3d1310f88b1f35e42c83cbee92e9ae41 100644 (file)
@@ -1,9 +1,10 @@
 import Data.List (foldl')        -- import the strict fold
 
 -- number of steps
-type Step = Int
+type Distance = Int
 type Position = (Int, Int)
 
+-- the directions. See below for functions for turning
 data Direction = North | East | South | West 
     deriving (Enum, Show, Bounded, Eq)
 
@@ -12,7 +13,8 @@ data Mowmaster = Mowmaster { direction :: Direction
                            , position :: Position
                            } deriving (Show, Eq)
 
-data Instruction =   Forward Step
+-- one instruction for the mowmaster
+data Instruction =   Forward Distance
                    | Clockwise 
                    | Anticlockwise
                    | Comment String
@@ -35,7 +37,6 @@ part2 instruction_text = finalDistance $ executeAll instructions
           executeAll = foldl' execute initialMowmaster
           
 
-
 -- Is this line a comment?
 isComment :: String -> Bool
 isComment ('#':_) = True
@@ -70,6 +71,7 @@ execute m  Clockwise     = m {direction = turnCW (direction m)}
 execute m  Anticlockwise = m {direction = turnACW (direction m)}
 execute m (Comment _)    = m
 
+
 -- Move in the current direction
 forward :: Int -> Direction -> Position -> Position
 forward s North (e, n) = (e, n+s)
@@ -77,7 +79,6 @@ forward s South (e, n) = (e, n-s)
 forward s West  (e, n) = (e-s, n)
 forward s East  (e, n) = (e+s, n)
 
-
 -- | a `succ` that wraps 
 turnCW :: (Bounded a, Enum a, Eq a) => a -> a 
 turnCW dir | dir == maxBound = minBound
index e67f48df5c27946c9b459c924f8395ff02d1a84d..1fdb8a1d5abb947572dd453bcc743fe623287195 100644 (file)
@@ -1,71 +1,7 @@
-# This file was automatically generated by 'stack init'
-#
-# Some commonly used options have been documented as comments in this file.
-# For advanced use and comprehensive documentation of the format, please see:
-# https://docs.haskellstack.org/en/stable/yaml_configuration/
-
-# Resolver to choose a 'specific' stackage snapshot or a compiler version.
-# A snapshot resolver dictates the compiler version and the set of packages
-# to be used for project dependencies. For example:
-#
-# resolver: lts-3.5
-# resolver: nightly-2015-09-21
-# resolver: ghc-7.10.2
-# resolver: ghcjs-0.1.0_ghc-7.10.2
-#
-# The location of a snapshot can be provided as a file or url. Stack assumes
-# a snapshot provided as a file might change, whereas a url resource does not.
-#
-# resolver: ./custom-snapshot.yaml
-# resolver: https://example.com/snapshots/2018-01-01.yaml
-resolver: lts-12.9
-
-# User packages to be built.
-# Various formats can be used as shown in the example below.
-#
-# packages:
-# - some-directory
-# - https://example.com/foo/bar/baz-0.0.2.tar.gz
-# - location:
-#    git: https://github.com/commercialhaskell/stack.git
-#    commit: e7b331f14bcffb8367cd58fbfc8b40ec7642100a
-# - location: https://github.com/commercialhaskell/stack/commit/e7b331f14bcffb8367cd58fbfc8b40ec7642100a
-#  subdirs:
-#  - auto-update
-#  - wai
+flags: {}
+ghc-options:
+  $locals: -O2 -Wall -Wno-missing-signatures -threaded -rtsopts -with-rtsopts=-N
 packages:
 - .
-# Dependency packages to be pulled from upstream that are not in the resolver
-# using the same syntax as the packages field.
-# (e.g., acme-missiles-0.3)
-# extra-deps: []
-
-# Override default flag values for local packages and extra-deps
-# flags: {}
-
-# Extra package databases containing global packages
-# extra-package-dbs: []
-
-# Control whether we use the GHC we find on the path
-# system-ghc: true
-#
-# Require a specific version of stack, using version ranges
-# require-stack-version: -any # Default
-# require-stack-version: ">=1.7"
-#
-# Override the architecture used by stack, especially useful on Windows
-# arch: i386
-# arch: x86_64
-#
-# Extra directories used by stack for building
-# extra-include-dirs: [/path/to/dir]
-# extra-lib-dirs: [/path/to/dir]
-#
-# Allow a newer minor version of GHC than the snapshot specifies
-# compiler-check: newer-minor
-
-ghc-options:
-  ! '$locals': -O2 -Wall -Wno-missing-signatures -threaded -rtsopts -with-rtsopts=-N
-
-extra-deps:
-- parsec-numbers-0.1.0
\ No newline at end of file
+extra-deps: []
+resolver: lts-12.9
index 77423a3484bdacd510e8c15a82c6e0920f500689..715e6cbdc43385bff8ead08af0d9482a061ad910 100644 (file)
@@ -32,3 +32,11 @@ executable task1
   main-is:             task1.hs
   default-language:    Haskell2010
   build-depends:       base >= 4.7 && < 5
+
+executable task1-mpc
+  hs-source-dirs:      src/task1
+  main-is:             task1-mpc.hs
+  default-language:    Haskell2010
+  build-depends:       base >= 4.7 && < 5
+                     , text
+                     , megaparsec