2021-10-01 00:04:16 +00:00
|
|
|
module Homework.Ch01.HanoiSpec where
|
|
|
|
|
|
|
|
import Homework.Ch01.Hanoi
|
|
|
|
import Test.Hspec
|
|
|
|
|
|
|
|
spec :: Spec
|
2021-10-06 19:12:47 +00:00
|
|
|
spec = describe "Hanoi" $ do
|
2021-10-06 21:49:48 +00:00
|
|
|
-- Testing the solver function
|
2021-10-06 19:12:47 +00:00
|
|
|
describe "hanoi" $ do
|
2021-10-06 21:49:48 +00:00
|
|
|
-- helper to construct a hanoi function with preconfigured labels
|
|
|
|
let hanoiOf = hanoi "a" "b" "c"
|
|
|
|
|
|
|
|
it "can solve for a stack of 1 disc" $ do
|
2021-10-07 14:06:19 +00:00
|
|
|
moves <- hanoiOf 1 -- a@[1] b@[] c@[]
|
|
|
|
moves
|
|
|
|
`shouldBe` [ Move "a" "c" -- a@[] b@[] c@[1]
|
|
|
|
]
|
2021-10-06 21:49:48 +00:00
|
|
|
|
|
|
|
it "can solve for a stack of 2 discs" $ do
|
2021-10-07 14:06:19 +00:00
|
|
|
moves <- hanoiOf 2 -- a@[2, 1] b@[] c@[]
|
|
|
|
moves
|
|
|
|
`shouldBe` [ Move "a" "c", -- a@[2] b@[] c@[1]
|
|
|
|
Move "a" "b", -- a@[] b@[2] c@[1]
|
|
|
|
Move "c" "a", -- a@[1] b@[2] c@[]
|
|
|
|
Move "a" "c", -- a@[1] b@[] c@[2]
|
|
|
|
Move "a" "c" -- a@[] b@[] c@[2, 1]
|
|
|
|
]
|
2021-10-06 21:49:48 +00:00
|
|
|
|
|
|
|
it "can solve for a stack of 3 discs" $ do
|
2021-10-07 14:06:19 +00:00
|
|
|
moves <- hanoiOf 3 -- a@[3, 2, 1] b@[] c@[]
|
|
|
|
moves
|
|
|
|
`shouldBe` [ Move "a" "c", -- a@[3, 2] b@[] c@[1]
|
|
|
|
Move "a" "b", -- a@[3] b@[2] c@[1]
|
|
|
|
Move "c" "b", -- a@[3] b@[2, 1] c@[]
|
|
|
|
Move "a" "c", -- a@[] b@[2, 1] c@[3]
|
|
|
|
Move "b" "a", -- a@[1] b@[2] c@[3]
|
|
|
|
Move "b" "c", -- a@[1] b@[] c@[3, 2]
|
|
|
|
Move "a" "c" -- a@[] b@[] c@[3, 2, 1]
|
|
|
|
]
|
2021-10-06 21:49:48 +00:00
|
|
|
|
2021-10-07 13:56:19 +00:00
|
|
|
{----------------------------------------------------------------------------}
|
|
|
|
{- MOVE ---------------------------------------------------------------------}
|
|
|
|
{----------------------------------------------------------------------------}
|
|
|
|
|
2021-10-06 21:49:48 +00:00
|
|
|
-- Testing individual moves
|
|
|
|
describe "move" $ do
|
|
|
|
it "moves the smallest peg from peg A to peg C if peg C's disc is bigger" $ do
|
|
|
|
let emptyPegs = initPegs "a" "b" "c" 0
|
|
|
|
pegs =
|
|
|
|
emptyPegs
|
|
|
|
{ pegsPegA = (emptyPeg "a") {pegDiscs = [Disc 3, Disc 1]},
|
|
|
|
pegsPegC = (emptyPeg "c") {pegDiscs = [Disc 2]}
|
|
|
|
}
|
2021-10-07 14:06:19 +00:00
|
|
|
|
|
|
|
-- run the function
|
|
|
|
(moveMade, pegsAfterMove) <- runPegs move pegs
|
2021-10-06 21:49:48 +00:00
|
|
|
|
|
|
|
-- a move should have been made
|
|
|
|
moveMade `shouldBe` Just (Move "a" "c")
|
|
|
|
-- the pegs should have changed
|
|
|
|
pegsAfterMove
|
|
|
|
`shouldBe` pegs
|
|
|
|
{ pegsPegA = (pegsPegA pegs) {pegDiscs = [Disc 3]},
|
2021-10-07 14:06:19 +00:00
|
|
|
pegsPegC = (pegsPegC pegs) {pegDiscs = [Disc 2, Disc 1]},
|
|
|
|
pegsMoves = [Move {moveFrom = "a", moveTo = "c"}]
|
2021-10-06 21:49:48 +00:00
|
|
|
}
|
|
|
|
|
2021-10-07 13:56:19 +00:00
|
|
|
{----------------------------------------------------------------------------}
|
|
|
|
{- PEGS ---------------------------------------------------------------------}
|
|
|
|
{----------------------------------------------------------------------------}
|
|
|
|
|
2021-10-06 21:49:48 +00:00
|
|
|
-- Testing constructor for a set of pegs
|
|
|
|
describe "initPegs" $ do
|
|
|
|
it "creates pegs with labels and fills the first peg with discs" $ do
|
|
|
|
initPegs "a" "b" "c" 3
|
|
|
|
`shouldBe` Pegs
|
|
|
|
{ pegsPegA = Peg {pegLabel = "a", pegDiscs = [Disc 3, Disc 2, Disc 1]},
|
|
|
|
pegsPegB = Peg {pegLabel = "b", pegDiscs = []},
|
2021-10-07 14:06:19 +00:00
|
|
|
pegsPegC = Peg {pegLabel = "c", pegDiscs = []},
|
|
|
|
pegsMoves = []
|
2021-10-06 21:49:48 +00:00
|
|
|
}
|
|
|
|
|
2021-10-07 13:56:19 +00:00
|
|
|
{----------------------------------------------------------------------------}
|
|
|
|
{- PEG ----------------------------------------------------------------------}
|
|
|
|
{----------------------------------------------------------------------------}
|
|
|
|
|
2021-10-06 21:49:48 +00:00
|
|
|
-- Testing constructor for a peg with discs
|
2021-10-06 20:39:05 +00:00
|
|
|
describe "fillPeg" $ do
|
2021-10-06 19:12:47 +00:00
|
|
|
it "creates a list of disks from biggest to smallest" $ do
|
2021-10-06 20:39:05 +00:00
|
|
|
fillPeg "a" 3
|
|
|
|
`shouldBe` Peg
|
|
|
|
{ pegLabel = "a",
|
2021-10-06 21:49:48 +00:00
|
|
|
pegDiscs = [Disc 3, Disc 2, Disc 1]
|
|
|
|
}
|
|
|
|
|
|
|
|
-- Testing constructor for a peg without discs
|
|
|
|
describe "emptyPeg" $ do
|
|
|
|
it "creates an empty peg" $ do
|
|
|
|
emptyPeg "a"
|
|
|
|
`shouldBe` Peg
|
|
|
|
{ pegLabel = "a",
|
|
|
|
pegDiscs = []
|
2021-10-06 20:39:05 +00:00
|
|
|
}
|
2021-10-06 21:49:48 +00:00
|
|
|
|
|
|
|
-- Testing constructor for a stack of discs
|
|
|
|
describe "stackDiscs" $ do
|
|
|
|
it "should create a stack of discs from largest to smallest" $ do
|
|
|
|
stackDiscs 3 `shouldBe` [Disc 3, Disc 2, Disc 1]
|