Last active
April 13, 2018 08:30
-
-
Save AndrewBestbier/b2e9a55628b2390fa8af215088f29bdf to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import Prelude | |
import Data.Complex | |
data CompassPoint = E | N | W | S deriving (Show, Enum) | |
type Position = Complex Double | |
type Point = (Position, CompassPoint, Int) | |
type ComplexPoint = (Point, [Point]) | |
-- Question 1 | |
question1 n = (\((x:+y), _) -> abs x + abs y) . last . take n $ iterate step1 ((0:+0), E) | |
-- Question 2 | |
question2 n = (\((_, _, x), _) -> x) $ last $ takeWhileInclusive (\((_, _, x), _) -> x < n) $ iterate step2 (((0:+0), E, 1), []) | |
-- Helpers | |
step1 :: (Position, CompassPoint) -> (Position, CompassPoint) | |
step1 ((0:+0), E) = (((1:+0), N)) | |
step1 (oldPosition, compassPoint) = (move oldPosition compassPoint, maybeRotate oldPosition newPosition compassPoint) | |
where newPosition = move oldPosition compassPoint | |
step2 :: ComplexPoint -> ComplexPoint | |
step2 (((0:+0), E, 1), []) = (((1:+0), N, 1), [((0:+0), E, 1)]) | |
step2 ((oldPosition, compassPoint, value), acc) = ((move oldPosition compassPoint, maybeRotate oldPosition newPosition compassPoint, newValue), newAcc) | |
where newPosition = move oldPosition compassPoint | |
newAcc = acc ++ [(oldPosition, compassPoint, value)] | |
newValue = findNewValue value newAcc newPosition | |
move :: Position -> CompassPoint -> Position | |
move (x :+ y) compassPoint = case compassPoint of | |
N -> (x :+ (y + 1)) | |
E -> ((x + 1) :+ y) | |
S -> (x :+ (y - 1)) | |
W -> ((x - 1) :+ y) | |
maybeRotate :: Position -> Position -> CompassPoint -> CompassPoint | |
maybeRotate (x1 :+ y1) (x2 :+ y2) compassPoint | |
| x1 > 0 && y1 < 0 && x1 == abs y1 = turnLeft compassPoint | |
| x2 == y2 = turnLeft compassPoint | |
| abs x2 == y2 = turnLeft compassPoint | |
| otherwise = compassPoint | |
turnLeft :: CompassPoint -> CompassPoint | |
turnLeft compassPoint = case compassPoint of | |
N -> W | |
W -> S | |
S -> E | |
E -> N | |
findNewValue :: Int -> [Point] -> Position -> Int | |
findNewValue oldValue acc newPosition = sum [z | ((x1:+y1), d, z) <- acc, (x2:+y2) <- surroundingPoints, x1 == x2, y1 == y2] | |
where surroundingPoints = findSurroundingPoints newPosition | |
findSurroundingPoints :: Position -> [Position] | |
findSurroundingPoints (x :+ y) = [((x + 1) :+ y), ((x - 1) :+ y), (x :+ (y + 1)), (x :+ (y - 1)), ((x + 1) :+ (y + 1)), ((x - 1) :+ (y + 1)), ((x - 1) :+ (y - 1)), ((x + 1) :+ (y - 1))] | |
takeWhileInclusive :: (a -> Bool) -> [a] -> [a] | |
takeWhileInclusive _ [] = [] | |
takeWhileInclusive p (x:xs) = x : if p x then takeWhileInclusive p xs | |
else [] |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
For improvement:
findSurroundingPoints
is inefficient as not all the points would be used.maybeRotate
is dodgy and could probably be done better. Also the Maybe part is misleadingCould take
getValue $ last $ takeWhileInclusive (\((_, _, x), _) -> x < 347991) $ iterate step (((0:+0), E, 1), [])
and make it into a nice single functionPerhaps there is a better implementation for
takeWhileInclusive
than some custom jobstep
is very wordy, possibly can be slimmed downComplexPoint
is not a great name