2021-10-01 00:04:16 +00:00
|
|
|
module Homework.Ch01.Hanoi where
|
|
|
|
|
2021-10-06 19:19:22 +00:00
|
|
|
import Data.Maybe
|
|
|
|
|
2021-10-01 00:04:16 +00:00
|
|
|
newtype Peg = Peg ()
|
|
|
|
|
|
|
|
data Move = Move {moveFrom :: String, moveTo :: String} deriving (Eq, Show)
|
|
|
|
|
2021-10-06 19:12:47 +00:00
|
|
|
data Disc = Disc {discSize :: Int} deriving (Eq, Show, Ord)
|
|
|
|
|
|
|
|
type Pegs = [(String, [Disc])]
|
2021-10-01 00:04:16 +00:00
|
|
|
|
|
|
|
hanoi :: Int -> String -> String -> String -> Either String [Move]
|
|
|
|
hanoi numDisks pegLabelA pegLabelB pegLabelC =
|
2021-10-06 19:12:47 +00:00
|
|
|
let pegs =
|
|
|
|
[ (pegLabelA, fillPegWithDiscs numDisks),
|
|
|
|
(pegLabelB, []),
|
|
|
|
(pegLabelC, [])
|
2021-10-01 00:04:16 +00:00
|
|
|
]
|
2021-10-06 19:19:22 +00:00
|
|
|
in Right . return . fromJust . fst $ move pegs
|
2021-10-06 19:12:47 +00:00
|
|
|
|
2021-10-06 19:19:22 +00:00
|
|
|
move :: Pegs -> (Maybe Move, Pegs)
|
2021-10-06 19:12:47 +00:00
|
|
|
move pegs =
|
|
|
|
let (firstPegLabel, firstPeg) = head pegs
|
|
|
|
(lastPegLabel, lastPeg) = last pegs
|
|
|
|
firstPegDisc = last firstPeg
|
|
|
|
lastPegDisc = last lastPeg
|
|
|
|
canMove = firstPegDisc < lastPegDisc
|
|
|
|
in if canMove
|
|
|
|
then
|
2021-10-06 19:19:22 +00:00
|
|
|
( Just $ Move firstPegLabel lastPegLabel,
|
|
|
|
[ (firstPegLabel, init firstPeg),
|
2021-10-06 19:12:47 +00:00
|
|
|
head $ tail pegs,
|
|
|
|
(lastPegLabel, lastPeg <> [firstPegDisc])
|
2021-10-06 19:19:22 +00:00
|
|
|
]
|
2021-10-06 19:12:47 +00:00
|
|
|
)
|
2021-10-06 19:19:22 +00:00
|
|
|
else (Nothing, [])
|
2021-10-06 19:12:47 +00:00
|
|
|
|
|
|
|
fillPegWithDiscs :: Int -> [Disc]
|
|
|
|
fillPegWithDiscs numDisks = Disc <$> reverse [1 .. numDisks]
|