-- given a state it returns all the valid states it can reach in one step
expandState :: State -> S.Seq State
expandState state = let
        -- items on the current floor
        allItems = getFloorItems state

        newItemsHelper :: S.Seq ItemSet -> Item -> S.Seq ItemSet
        newItemsHelper s i =
            i S.<| foldl (\ss ii -> (i .|. ii) S.<| ss) s
                (expandItemSet allItems (i `unsafeShiftL` 1))

        -- pairs of items it can move
        newItems :: S.Seq ItemSet
        newItems = foldl newItemsHelper S.empty $ expandItemSet allItems 1

        -- states when trying to move down
        sdown = if getFloor state == 0 then S.empty else
            S.filter checkState $ fmap (moveDown state) newItems

        -- states when trying to move up
        sup = if getFloor state == 3 then S.empty else
            S.filter checkState $ fmap (moveUp state) newItems
    in
        sup S.>< sdown
expandState :: State -> S.Seq State
expandState state = let
        -- items on the current floor
        allItems = getFloorItems state

        newItemsHelper :: S.Seq ItemSet -> Item -> S.Seq ItemSet
        newItemsHelper s i =
            i S.<| foldl (\ss ii -> (i .|. ii) S.<| ss) s
                (expandItemSet allItems (i `unsafeShiftL` 1))

        -- pairs of items it can move
        newItems :: S.Seq ItemSet
        newItems = foldl newItemsHelper S.empty $ expandItemSet allItems 1

        -- states when trying to move down
        sdown = if getFloor state == 0 then S.empty else
            S.filter checkState $ fmap (moveDown state) newItems

        -- states when trying to move up
        sup = if getFloor state == 3 then S.empty else
            S.filter checkState $ fmap (moveUp state) newItems
    in
        sup S.>< sdown
expandState state = let
        -- items on the current floor
        allItems = getFloorItems state

        newItemsHelper :: S.Seq ItemSet -> Item -> S.Seq ItemSet
        newItemsHelper s i =
            i S.<| foldl (\ss ii -> (i .|. ii) S.<| ss) s
                (expandItemSet allItems (i `unsafeShiftL` 1))

        -- pairs of items it can move
        newItems :: S.Seq ItemSet
        newItems = foldl newItemsHelper S.empty $ expandItemSet allItems 1

        -- states when trying to move down
        sdown = if getFloor state == 0 then S.empty else
            S.filter checkState $ fmap (moveDown state) newItems

        -- states when trying to move up
        sup = if getFloor state == 3 then S.empty else
            S.filter checkState $ fmap (moveUp state) newItems
    in
        sup S.>< sdown