I struggled for a long time because I had nearly the correct results. I had to switch div with quot.
This puzzle was fun. If you have a visualization, it's even cooler. (It's a fractal)
Haskell Code
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE PatternSynonyms #-}
{-# OPTIONS_GHC -Wall #-}
module Main (main) where
import Text.Read (ReadPrec, Read (readPrec))
import Data.Functor ((<&>))
import Data.Text (pattern (:<), Text)
import qualified Data.Text as Text
import qualified Data.Text.IO as TextIO
import Control.Monad ((<$!>))
import Control.Arrow ((<<<))
newtype Complex = Complex (Int, Int)
instance Read Complex where
readPrec :: ReadPrec Complex
readPrec = readPrec <&> \case
[a, b] -> Complex (a, b)
_ -> undefined
instance Show Complex where
show :: Complex -> String
show (Complex (a, b))= show [a, b]
readAEquals :: Text -> Complex
readAEquals ('A' :< '=':< rest) = read $ Text.unpack rest
readAEquals _ = undefined
-- >>> Complex (1, 1) `add` Complex (2, 2)
-- [3,3]
add :: Complex -> Complex -> Complex
(Complex (x1, y1)) `add` (Complex (x2, y2)) = Complex (x1 + x2, y1 + y2)
-- >>> Complex (2, 5) `times` Complex (5, 7)
-- [-25,-11]
times :: Complex -> Complex -> Complex
(Complex (x1, y1)) `times` (Complex (x2, y2)) = Complex (x1 * x2 - y1 * y2, x1 * y2 + x2 * y1)
dividedBy :: Complex -> Complex -> Complex
(Complex (x1, y1)) `dividedBy` (Complex (x2, y2)) = Complex (x1 `quot` x2, y1 `quot` y2)
step :: Complex -> Complex -> Complex
step a r = let
r1 = r `times` r
r2 = r1 `dividedBy` Complex (10, 10)
r3 = r2 `add` a
in r3
zero :: Complex
zero = Complex (0, 0)
part1 :: Complex -> Complex
part1 a = iterate (step a) (Complex (0, 0)) !! 3
shouldBeEngraved :: Complex -> Bool
shouldBeEngraved complexPoint = let
cycleStep :: Complex -> Complex -> Complex
cycleStep point r = let
r2 = r `times` r
r3 = r2 `dividedBy` Complex (100000, 100000)
in point `add` r3
inRange x = x <= 1000000 && x >= -1000000
in all (\ (Complex (x, y)) -> inRange x && inRange y)
<<< take 101
<<< iterate (cycleStep complexPoint)
$ zero
-- >>> shouldBeEngraved $ Complex (35630,-64880)
-- True
-- >>> shouldBeEngraved $ Complex (35460, -64910)
-- False
-- >>> shouldBeEngraved $ Complex (35630, -64830)
-- False
part2 :: Complex -> Int
part2 (Complex (xA, yA)) = let
xB = xA + 1000
yB = yA + 1000
in length . filter shouldBeEngraved $ do
x <- [xA, xA+10.. xB]
y <- [yA, yA+10.. yB]
pure $ Complex (x, y)
part3 :: Complex -> Int
part3 (Complex (xA, yA)) = length . filter shouldBeEngraved $ do
x <- [xA..xA+1000]
y <- [yA..yA+1000]
pure $ Complex (x, y)
-- >>> [0, 10..100]
-- [0,10,20,30,40,50,60,70,80,90,100]
main :: IO ()
main = do
a <- readAEquals <$!> TextIO.getContents
print $ part1 a
print $ part2 a
print $ part3 a
My girlfriend is learning python, we are taking on the challenges together, today I may upload her solution:
python
A=[-3344,68783]
R = [0, 0]
B= [A[0]+1000, A[1]+1000]
pointsengraved = 0
cycleright = 0
for i in range(A[1], B[1]+1):
for j in range(A[0], B[0]+1):
for k in range(100):
R = [int(R[0] * R[0] - R[1] * R[1]), int(R[0] * R[1] + R[1] * R[0])]
R = [int(R[0] / 100000), int(R[1] / 100000)]
R = [int(R[0] + j), int(R[1] + i)]
if -1000000>R[0] or R[0]>1000000 or -1000000>R[1] or R[1]>1000000:
#print(".", end="")
break
cycleright += 1
if cycleright == 100:
pointsengraved += 1
#print("+", end="")
cycleright = 0
R = [0, 0]
#print()
print(pointsengraved)
The commented out print statements produce an ascii map of the set, which can be cool to view at the right font size.