Gena Playing Hanoi

  • + 1 comment

    C++ (more at https://github.com/IhorVodko/Hackerrank_solutions , feel free to give a star:) )
    Build bfs tree where each node is a game state.

    static const size_t rodsCount = 4;
    static const size_t statesMaxCount = static_cast<size_t>(std::pow(4, 10)); 
    
    size_t hanoi(
        std::vector<size_t> const & positions
    ){
        using namespace std;
        using state_t = vector<size_t>;
        using mask_t = vector<bool>;
        auto const & disksCount{positions.size()};
        // last element of a vector tracks how many moves done to achive its state
        auto stateAtTreeRoot(state_t(disksCount + 1, 0));
        transform(cbegin(positions), cend(positions), begin(stateAtTreeRoot),
            [&](const auto & disk){
                return disk - 1;
            });
        auto bfsQ{queue<state_t>{}};
        bfsQ.push(stateAtTreeRoot);
        auto statesAtTreeVisited{mask_t(::statesMaxCount, false)};
        auto hash = [&](auto const & value){
            size_t hashValue{0};
            for_each(cbegin(value), cend(value) - 1, [&](auto const & num){
                hashValue = hashValue * ::rodsCount + num;
            });
            return hashValue;
        };
        statesAtTreeVisited.at(hash(stateAtTreeRoot)) = true;
        auto rodsVisitedToMoveFrom{mask_t(::rodsCount, false)};
        auto rodsVisitedToMoveTo{mask_t(::rodsCount, false)};
        size_t hashValue{0};
        auto stateAtSubTreeRoot{state_t(disksCount + 1, 0)};
        auto stateAtNextNode{state_t(disksCount + 1, 0)};
        while(!bfsQ.empty()){
            copy(cbegin(bfsQ.front()), cend(bfsQ.front()),
                begin(stateAtSubTreeRoot));
            bfsQ.pop();
            for(size_t disk{0}; disk < disksCount; ++disk){
                if(rodsVisitedToMoveFrom.at(stateAtSubTreeRoot.at(disk))){
                   continue; 
                }
                rodsVisitedToMoveFrom.at(stateAtSubTreeRoot.at(disk)) = true;
                copy(cbegin(rodsVisitedToMoveFrom), cend(rodsVisitedToMoveFrom),
                    begin(rodsVisitedToMoveTo));
                for(size_t newRod{0}; newRod < ::rodsCount; ++newRod){
                    if(rodsVisitedToMoveTo.at(newRod)){
                        continue;
                    }
                    rodsVisitedToMoveTo.at(newRod) = true;
                    copy(cbegin(stateAtSubTreeRoot), cend(stateAtSubTreeRoot),
                        begin(stateAtNextNode));
                    ++stateAtNextNode.back();
                    stateAtNextNode.at(disk) = newRod;
                    hashValue = hash(stateAtNextNode);
                    if(hashValue == 0){
                        return stateAtNextNode.back();
                    }
                    if(statesAtTreeVisited.at(hashValue)){
                        continue;
                    }
                    statesAtTreeVisited.at(hashValue) = true;
                    bfsQ.push(stateAtNextNode);
                }
                fill(begin(rodsVisitedToMoveTo), end(rodsVisitedToMoveTo),
                    false);
            }
            fill(begin(rodsVisitedToMoveFrom), end(rodsVisitedToMoveFrom),
                false);
        }
        return numeric_limits<size_t>::max();
    }